currentValue for function

I’m rather disappointed by the new function. The main problem I have is that they can’t have anny knowledge of the titles in the filter run. This is logical as they are not filter operator.

But “function” is a filter operator. As such, could it be made to know the current title in the filter run (not the currentTiddler!)? If so let’s call it currentTitle and somethng like this could me made:

\function .double(n) [<n>add<n>]

{{{ [range[5]function[.double],<currenTitle>] }}}

This code is nothing but a simple example. It could be written without this new scheme. This is not the topic of this message.

1 Like

Well, no, because it operates on the current titles supplied as its input (it sounds as though you want it to be a Selection Constructor, but it’s not).

Try this:

\function .double() [multiply[2]]

{{{ [range[1],[5]] :map[function[.double]] }}}

These might help you move forward…

\function .double() [multiply[2]]
\function .dbl(n) [<n>add<n>]
\function .square(n) [<n>multiply<n>]

1: 

{{{ [range[1],[5]] :map[.double[]]  }}}

2:

{{{ [range[1],[5]] :map[.dbl<currentTiddler>]  }}}

3: 

{{{ [range[1],[5]] :map[.square<currentTiddler>] }}}

Thank you @CodaCoder: that’s exactly what I wanted.

Now, what I would like to do in a filter would be like:

{{{ [range[5]match[3]then<.double>else<.square>]  }}}

where these function would do as in your examples. In this code example, <.double> is pseudo-code for “calling function .double”. This is not possible as of now. But it would really be a very cool feature.

One could even hope for something with other explicit arguments:

{{{ [range[5]match[3]then[.double],[42]else[.square],[root],[66]]  }}}

I’m thinking it could be done, if “then” and “else” get the “function” capacities that are required to do that magic. After all, the code below is valid (but dumb):

{{{ [range[5]match[3]function[.double],[42]function[.square],[root],[66]]  }}}

Agreed. This would be very useful! I spend a lot of time doing functional programming in JS, and sometime TW seems like a great fit. After all, the filter syntax feels quite like FP-style declarative coding. But I would love to have simple references to functions that would act like functions.

I am not sure I see the limitations with functions in tiddlywiki although they may not be they same as functions in other languages. Here is a summary of the ways I have used them.

  • they can be used as variables. First result only
  • they can be used as a list, use join in its definition. Everything is the first result. You may need to subsequently enlist it.
  • they can be called with the function filter operator
  • they can be called by name as a custom operators with parameters
  • they can generate a list or process a list of titles
  • they can be used as a subfilter to divide complex filters into semantic ones
  • their output can be used without wikification first
  • they can display their result a text without needing the $text widget

To name a few

\function tag.list(tagname) [tag<tagname>format:titlelist[]join[]]
\function tag.children() [tag<currentTiddler>format:titlelist[]join[]]

<<tag.list TableOfContents>>
<hr>

{{{ [<tag.children>] }}}

Any apparent gaps please help me understand so I can investigate. I am trying to gain a deep understanding.

Your first example does not make sense: {{{ [range[5]match[3]] }}} only returns 1 title which is 3. So there is no else path.

1 Like

No, but the point applies if you add a :map as in @CodaCoder’s examples.

{{{ [range[1],[5]] :map[match[3]then<.double>else<.square>]  }}}
<!--                                ^^^^^^^^^    ^^^^^^^^^   -->

Is there simple syntax that would go in the marked spots so that this would generate 1 4 6 16 25?

1 Like

Untested code but should be in the right ballpark:

\function .dbl(n) [<n>add<n>]
\function .square(n) [<n>multiply<n>]
\function dbl.or.square(n) [<n>match[3]] :then[.dbl<n>] :else[.square<n>]

{{{ [range[1],[5]]  :map[dbl.or.square<currentTiddler>]}}}

or


\function .double() [multiply[2]]
\function .square() [all[]] :map[<currentTiddler>multiply<currentTiddler>]
\function dbl.or.square(n) [all[]match[3]] :then[.double[]] :else[.square[]]

{{{ [range[1],[5]]  :map[dbl.or.square[]] }}}

@saqimtiaz Tgank you. This is indded a solution.

But a solution that reqires a :map and thus an independent filter run.

If I take your functions that produce no list, I think it legitimate to wish for being able to directly write:

{{{ [{!!score}match[3]then[.double]else[.square]] }}}

it would just need that every function has a default argument that would be equal to what called currentValue. This would allow the direct use of your functions as they are currently written. And simplify writing filters.

Perhaps instead of the then else operators which are somewhat limited have a look at the then and else filter run prefixes, because you can do more in a filter run.

@TW_Tones Yes fliter run are powerful.

Here a way of using it within a function (I was not aware I could have several filter runs inside a function without writing this snippet):

\function .doubleOrSquare(n)
[<n>match[3]then[.double]else[.square]]
:map[<n>function<currentTiddler>,<n>]
\end

But… what if we could use suffix for function that would trigger the availability of special variable into function just like filter run prefix do for filter runs? This would give access to currentTiddler as the current value in the filter data.

And an other idea: in my example, I need to use the “map” filter prefix to be able to call the function whose name is on the top of the filter data stack. It would be handy to have a call filter op that would po that name from the stack and call the function of the same name (with the stack now without that name). It would allow for the following simple code:

\function .doubleOrSquare(n)
[<n>match[3]then[.double]else[.square]]call<n>]
\end

that “call” filter op would allow some easy coding of expressive filters.

Yes, that works fine. My question (which I think is related to the original point from @jypre) is not really about how to create an odd double-or-square function, but how to dynamically call functions by name inside a filter. It seems that it is not possible, but I may still be missing it.

Could you explain what the all[] expressions do in these?

.square could clearly be rewritten to match the simpler, .double:

\function .square() [power[2]]

(and I really like these as forms of point-free functions!)

But I can’t find a way to do away with the all[] in the second one. I can’t replace it with <n> or <__n__> or !n!, which are the types of magical guesses I often try when I can’t get a variable properly inserted into a filter. And in fact the n parameter is unimportant. The function still works fine without it. But I really don’t get what all[] is doing in this context.

The function-operator can handle dynamically named functions

\function one() function one text +[join[ ]]
\function two(x:"x-default") [[22222222222222 $(x)$]substitute[]] +[join[ ]] 

\function getFunctionName() [{/temp/select}trim[]]

<$tiddler tiddler="/temp/select">
<$radio value="one"> one</$radio>
<$radio value="two"> two</$radio>
</$tiddler>

<$let dyn-value="dyn" >

{{{ [function<getFunctionName>,<dyn-value>]  }}}

or if you want them as separated values you use `enlist-input`

{{{ [function<getFunctionName>,<dyn-value>enlist-input[]]  }}}

I am returning to the Original Topic as I am having trouble following the discussion, in part because it contains false assumptions and assertions.

It does know the current title, In fact the title is implied.

  • Think of a function as a subfilter if you have made use of them.

Let me illustrate with the “non-example” given;

\function .double() [multiply[2]]
\function .square() [power[2]]
\function .compute() [match[3].double[]] ~[power[2]]

<$list filter="[range[5]]">
<<currentTiddler>>={{{ [all[current].compute[]]   }}}
</$list>

and

{{{ [range[5]] :map[.compute[]] }}}
  • This produces the result as expected in both cases, 3 is only doubled the rest are squared.
  • Note: we use map to force an additional filter on all results prior, the same is available inside a list

Note:

  • CurrentTiddler, storyTiddler etc… can be used inside your function or custom operator however you are responcible for ensuring it has the appropriate value.
\function .simple() [<currentTiddler>addprefix[item-]]
<$list filter="[range[5]]">
<<currentTiddler>>={{{ [all[current].simple[]]   }}}
</$list>

Please tell me if other questions arrose later in this topic that are outstanding

Post script:
I see in other conversations that confuse me, my bad, I dont like unrealistic functions or variable names, I prefer to use real world examples, mataphor and analogues. However within these conversations I read little assaumptions and implications that I see are incorect. But the converstion is too complex for me to interupt.

For example: One key advantage of functions is they help you avoid the old bugbear of needing to use Wikify at the last step to “evaluate” at least anything you can do in a filter. SImilarly nthey avoid the need to use the text widget to present simple text and not be treated as a tiddler title.

I think that this would require a change to the way that functions are invoked.

At the moment, functions are invoked once, and are passed the entire input list as an implicit parameter. Thus there would only be one value for a variable like “currentValue”; the only way to pass the input list would be to encode it as a stringified list or a JSON array.

To do what you suggest, we would instead have to execute the function once for each result in the input list. That way each invocation could get a separate value for a variable like “currentValue”.

The reason we decided against that approach is that it makes it impossible to, say, create a function that duplicates the behaviour of the join operator.

But, perhaps we could add a suffix to the function operator to cause the function to be invoked once for each item in the input list:

[enlist<mydata>function:each<myfunction>]

We could make the input item available in a variable called currentValue as you suggest.

1 Like

@TW_Tones I would not have thought of :else filter prefix to achieve an else operation! Thanl you for this one.

Otherwise, your points are valid, but I wanted to make all computation happen within a filter if possible.

@jeremyruston Your last suggestion is the right answer to my query!

And we really need a thourough documentation about functions. What they do and what they don’t do, and how to use them in realistic uses or in duplicating other functionality.

And I have to say, I cannot duplicate the join operator with a .join function… without using the join operator. The reduce operator should do the trick, but I can’t do it within a function (I need a variable). This problem I shall beg you all about in an other topic for clarity’s sake.

1 Like

Hi @Scott_Sauyet, I formulated that set of examples specifically to highlight the possibility of using the all[] operator to get access to the titles passed into a filter run or a custom filter, rather than using a parameter. This allows more flexibility writing functions to be used as selection modifiers, that is be chained on to a sequence of other operators. The second form of dbl.or.square should not accept a parameter at all as it is never used.

From the docs for the all operator:

As a special case, if the parameter is empty, the output is simply a copy of the input.

Filter run prefixes such as :map need to be preceded by a selection constructor and using the all operator meets that requirement and just passes on any input to that function or filter run.

3 Likes

Thank you. Now and then I start to feel I’m getting a real handle on TW. Other times, I see how far away a deep understanding really is!