How to CASCADE a function-stored-in-a-variable-that-has-multiple-arguments

There are three ways to use a function with CASCADE:
CASCADE is a function from the "Iteration, composition" library. It repeatedly applies a function, first to a specified initial value, and to the result of the previous step from then on - in other words: if the function is f(x), then CASCADE (3) TIMES ( f) (x) (#) means: f ( f ( f (x))), with “#” being an upvar that at any time during the cascade signifies the present “round” (which can be used as an argument of the function).

  1. as a regular function, e.g.: AoC 2023 day 5 script pic (1), with AoC 2023 day 5 script pic (2)

  2. as an anonymous function, e.g.: AoC 2023 day 5 script pic (4)

  3. as a variable, e.g.: AoC 2023 day 5 script pic (5).

But what if the function has multiple arguments? E.g. two-way addition:
the # upvar is 1 at the first round, and 2 at the second round. 1st: 3 + 1 = 4; 2nd: 4 + 2 = 6

  1. as a regular function: AoC 2023 day 5 script pic (6), with AoC 2023 day 5 script pic (9)

  2. as an anonymous function: AoC 2023 day 5 script pic (7)

  3. as a variable: AoC 2023 day 5 script pic (8) - take note of the CALL block in this final example; it won’t work without CALL !

This topic was originally phrased as a request for help regarding the final example; while I was writing it I found the solution, and decided to make it a mini-Tutorial.

Thanks for this. I wish more people knew about CASCADE!

I have a few quibbles.

In both of the numbered lists, I don't understand the word "as" at the beginning of each item. It seems to be suggesting that you can choose to use any function in any of the three ways, but I think what you really mean is that you can use named functions from the palette, you can use a ringed (anonymous) reporter, or you can use a reporter that's the value of a variable. I think the one about variables isn't like the other two because they're about what counts as a function, whereas the third one is about where you put the function, and isn't general enough. For example, you can put a function in a list, as in the project Open > Examples > vee:
shapes
and therefore you can put an (unringed) ITEM block in that second input to CASCADE. My point isn't that you should add a fourth list item for ITEM! You could write a custom block that reports a function, like this:
vee script pic


Note that the MAKE ADDER block is unringified in the CASCADE input slot! That's very important. You're not calling the function MAKE ADDER three times; you're calling the function MAKE ADDER before CASCADE runs, and the cascaded function is the one MAKE ADDER reports, which in this case is basically
vee script pic (2)

So you don't want a zillion special cases in a list; what you want to say is that as always in Snap! any expression can go in any input slot as long as it provides an input that the calling function understands.

For multi-input functions, you don't explicitly say that the expression you provide should generally fill all but one hole, so
vee script pic (3) No
vee script pic (4) Yes
vee script pic (5) No

But sometimes you do have more than one empty slot, in which case the old value goes into all the open slots.

Also you don't explain what the # upvar means, so your examples are unclear.

And finally, you should also explain
vee script pic (6)
not forgetting my favorite example:

vee script pic (9)

actually i did this after reading the initial post wondering what that is.

i still dont get it lmao

For a function f(x), calling cascade(3) is the equivalent of f(f(f(x))). It also has an upVar for the last round and allows you to set an initial value for x.

that is much better explanation, thanks

I actually did mean to suggest any function may be used in any of these ways (a list item is just a variable within this context). Though perhaps your interpretation of “function” is more rigid than mine. From my perspective (1) AoC 2023 day 5 script pic and (2) AoC 2023 day 5 script pic 2 are the same function, as both have the same definition - admittedly this may be somewhat different in case of a primitive function one doesn’t know the definition of.
What took me some time to find out is how to get arguments other than the seed, or the result of the previous iteration, fed into the function (in case 3). I tried stuff like

, and various other expressions I don’t all remember, until finally arriving at the solution.

BTW one reason for my sometimes wanting to use a variable-as-function is that I prefer to have all related code in a single script (for maintaining an overview), while keeping the main code simple.

Thx, I’ll add that to my OP.

I’ll leave that to you :slight_smile:

Even in pig latin, letters aren’t jumbled, nor is -ay an ending. Perhaps you meant something like: LINGVA PROGRAMMANDI SCHEMAE ?Oops, I confused it with dog latin.

Ah. Technically, they are the same function, because for the same input they give the same output. But they're not the same procedure, because their definitions are different. The second one calls a primtive with one of its inputs filled in; the first one is a custom block that calls the first one. My usual example is this:
untitled script pic (7) untitled script pic (6)
F and G are the same function, but different procedures. But I guess I don't think the different procedures in your example are very interesting, because there are infinitely many possible procedures to compute this function:
untitled script pic (8)

and so on.

untitled script pic (10)
F is a function of two inputs. This ringed expression is a function of one input that calls F. Doesn't that work? You don't put F(X,Y) in a ring because the value of that variable is the function you want to call, so you have to evaluate the variable to get the function.

Hmm, this leads me to suspect that you're still not getting #. It represents the number of invocations so far of the function. See if this helps:


If # meant the result so far, it'd be the same as an empty slot.

Oh wait, are you thinking that the # at the end of the line is an expression dragged into a second Any-type input slot in CASCADE?

Or am I not understanding what you're thinking?

I used this function (+1) as a simple example, so as for readers of my post to focus on the real issue: how to specify a callback-function-that-is-stored-in-a-variable-and-has-multiple-arguments (I’d like something less verbose, but that would probably be less precise) when calling CASCADE. So IMO this discussion about the +1 function is a bit off-topic.

Yes, I see now. CALL (variable) W/INPUTS ()() is itself a wrapper function that calls the function stored in the variable.

My initial confusion was caused by the fact that one can simply specify the variable containing F as a callback if F expects merely a single argument, like with:

AoC 2023 day 5 script pic 6

Of course it wouldn’t harm to use

instead, but that’s not necessary because CASCADE is already taking care of the CALL W/INPUTS thing.

No, that has been clear to me all along.

Provided there's a ring around it. :~)

This is a piece of magic in the evaluation of gray rings. Except for exceptions, any expression you put in a ringed input slot will retain the ring from the slot. The main exception is an expression consisting of just a variable; in this case, the ring is deleted. Once in a while this confuses someone, but it's an example of Do What I Mean™ evaluation. (It might actually be a trademark, for all I know; it's the name of a program by Warren Teitelman.) Namely, when you drag a variable into a ringed slot, you always mean that the variable's value is the function to call, i.e., you want the variable evaluated to get the function, i.e., it can't be in a ring. I'm not sure there are any other excepttions, although we considered making another exception for ITEM _ OF. It's a tricky decision because in the case of a list of functions as the second input to ITEM, you do want to evaluate it now to get the right function, not later. But that's far less likely than the case of a list of anything but functions.