Chains
Here’s something you probably haven’t had before. ## passes a value along
to the next step, and _ is the value that arrived.
FUNCTION double(n)
RETURN n * 2
END FUNCTION
FUNCTION shout(text)
RETURN UPPER(text) + "!"
END FUNCTION
result = 4 ## double(_) ## "the answer is " + _ ## shout(_)
PRINT result
THE ANSWER IS 8!
Read it left to right: start with 4, double it, put words in front, shout it.
Without the chain you’d write it inside out:
shout("the answer is " + double(4)).
A chain can run over several lines, one step to a line. A statement can be nothing but a chain, too, as long as it starts by calling something.
FUNCTION only_big(list, least)
LOCAL kept = []
FOR item = list
IF item >= least THEN PUSH kept, item
END FOR
RETURN kept
END FUNCTION
FUNCTION total(list)
LOCAL sum = 0
FOR item = list
sum = sum + item
END FOR
RETURN sum
END FUNCTION
scores = [5, 12, 8, 30]
only_big(scores, 10)
## total(_)
## PRINT "big ones add up to", _
big ones add up to 42
Notice that _ can go anywhere in the step: first argument, second, in the
middle of a sum. Any function will do, just as it was written.
Spreading the value out
So far _ has gone into the next step as one argument. Often the value
coming along is really several: a pair of numbers, a set of options. That’s
what the spread operator, **, is for. You met it in
Functions; it earns its keep here.
**_ hands a list to the next step as separate arguments, in order.
FUNCTION area(width, height)
RETURN width * height
END FUNCTION
FUNCTION size_of(room)
RETURN [room.wide, room.deep]
END FUNCTION
kitchen = {wide: 3, deep: 4}
floor = kitchen ## size_of(_) ## area(**_)
PRINT floor
12
size_of gave back one list, and area wanted two numbers. **_ is the
join between them, so neither function had to know about the other.
A map spreads too, into arguments by name. That makes a chain a tidy way to build up options and hand them over.
FUNCTION greet(who, greeting = "Hello", mark = "!")
RETURN greeting + ", " + who + mark
END FUNCTION
FUNCTION excited(options)
options.mark = "!!!"
RETURN options
END FUNCTION
said = {greeting: "Welcome"} ## excited(_) ## greet("Ada", **_)
PRINT said
Welcome, Ada!!!
You can mix the two in one step: ordinary arguments, _ as it is, and
**_ spread out.
FUNCTION total(first, rest...)
LOCAL sum = first
FOR value = rest
sum = sum + value
END FOR
RETURN sum
END FUNCTION
sum = [1, 2, 3] ## total(100, **_)
count = [1, 2, 3] ## LEN(_)
PRINT sum, count
106 3
From Python: No more reading
f(g(h(x)))from the inside out.
From JavaScript: Like method chaining with
., except the next step can be any function at all, and you choose where the value goes.
From Lua: Same idea as
:chaining, without needing a method for it.
From Python:
**_is your*argsand**kwargsat the call, in one operator: a list spreads in order and a map spreads by name.
From JavaScript:
**_is...valuefor a list. For a map it fills parameters by name, which a spread object can’t do for you.
Crash-tan’s Tip: Every step after the first has to use
_somewhere, spread or whole. If one doesn’t, the value would be thrown away, and I’ll say so before the program runs.