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:
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).
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:
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):
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
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.
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:
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:
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.
\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[]] }}}
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.
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.
@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.
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.