- 
                Notifications
    You must be signed in to change notification settings 
- Fork 5
Functions and tuples
The tuple holds a special place in the type system. As we have seen, it is constructed simply by concatenating values with commas: 1, true, "walrus" is a tuple. We can surround it with parentheses: (1, true, "walrus"), or we can emphasize the fact that it is a tuple with the tuple keyword and write tuple(1, true "walrus"), but these all refer to the same thing.
The purpose of the tuple type is to be completely invisible and something that you can completely take for granted. Nonetheless, we should still look at why it exists and how it works.
When passed to a function, tuples split up into their component parts.
If this wasn't true, it wouldn't be possible to pass multiple values to a function at all! Consider the following function, one of several example functions defined in examples/tuples.pf
swap (x, y) : y, x
When we call (e.g.) swap 1, 2, then from the definition of a tuple above, we are in fact passing it the tuple 1, 2. But tuples break up into their component parts when you pass them to functions, and so the 1 gets assigned to x and the 2 gets assigned to y.
There is no way to stop a tuple from deconstructing itself like this. If you want a type that doesn't do that, you should use a list.
You can, however, gather up any number of arguments into a single tuple parameter by giving the type of that parameter as tuple.
(Recall in the following example that you use arity and not len to get the number of elements in a tuple.)
rotateLeft(t tuple) : 
    t == () : 
        ()
    else : 
        t[1::arity t] , t[0]
The tuple-typed parameter of a function need not be the only parameter. For example, this works just fine:
Direction = enum LEFT, RIGHT
rotate(d Direction, t tuple) : 
    t == () : 
        ()
    d == RIGHT : 
        t[arity(t) - 1] , t[0::arity(t) - 1]
    else : 
        rotateLeft t
But if you put the parameters the other way round (i.e. rotate(t tuple, d Direction)) then Pipefish would throw an error when you tried to call it with rotate 1, 2, 3, LEFT because all four elements would be absorbed by the tuple.
To get round this, if we wanted to, we could define for example a function rotate(t tuple) to (d Direction), thus removing the concatenating comma. This is particularly useful if you want a function with more than one tuple parameter.
Again, the very definition of a tuple means that if you return more than one value from a function, you are in fact still returning one value, namely one tuple! You can't prevent that from happening either.
But when you put that together with the way tuples deconstruct themselves when passed to a function, you find that 99% of the time the net result is that you don't have to think about tuples or know that they exist. For example, if you run examples/tuples.pf, you will find that it will interpret an expression like rotateLeft ((swap 1, 2) , (swap 3, 4)) correctly without you having to remember that tuples are a type. This is why tuples are like that.
The one case where you do have to remember that tuples are a type is when you've written a function to return multiple values and then you find a circumstance where you want to call the function but then consume just one or two of those values rather than all of them. At this point it's useful to remember that your multiple return values are in fact a tuple, and to start indexing and slicing it.
Concatenating an empty tuple with something else will usually have no effect: since tuples are flat, true, "foo", () evaluates to true, "foo".
However, if you pass an empty tuple to a function expecting a tuple, then it will as it were register its existence. So if we have functions like this:
zort :
    "No parameters"
zort(t tuple) :
    "Tuple"
zort(s single) :
    "Single"
zort(x single, y tuple) :
    "Single, then tuple"
... then calling zort will call the first of them but zort() will call the second; zort 42 will call the third but zort 42, () will call the fourth.
🧿 Pipefish is distributed under the MIT license. Please steal my code and ideas.