Skip to content

Functions

bkul edited this page Jun 29, 2016 · 2 revisions

Functions

There are types of function in Fith: named and anonymous. They have roughly the same semantics; the difference is in how they are created and invoked.

Defining a Named Function

To demonstrate, here's a named function that adds one to its argument:

: increment ( x -- x+1 ) 1 + ;

That's a lot of strange-looking syntax. Let's break it down.

Starting a definition

: begins a function definition. It must be followed by the name of the function, which in this case is increment.

Stack Effects

The thing in parentheses that follows the name is called a stack effect. It shows how the function transforms the stack. It takes the form:

( before -- after )

where before and after are sequences of words representing the top few places on the stack. For example, here's the stack effect of swap, which swaps the top two values on the stack:

( x y -- y x )

Note that by convention, the right end of each stack diagram represents the top.

Inside the Function

After you've declared the name and stack effect, you write the function as if the name of the function were replaced with its contents every time it was invoked (which is pretty much what happens). For example, in our increment function, we assume that the argument is already present.

Closing a Declaration

To close your declaration, simply write the ; word. In case you're wondering, the : and ; syntax was inherited from Forth.

Creating an Anonymous Function

Anonymous functions have syntax similar to PostScript. You begin a block with { and end it with }. There are no explicitly written stack effects for anonymous functions. With that in mind, here's a version of the increment function from earlier, implemented anonymously:

{ 1 + }

After these words are executed, the top of the stack will be a function object. You can run function objects with the ~ word. So

3 { 1 + } ~

is the same as

3 1 +

Naming an Anonymous Function

There's one case we haven't really covered. What if you want to be able to call an anonymous function like a named function? In other words, to be able to do this:

{ 1 + } ???
## ...
3 increment

What would you put in place of ???? Fith has a word for that: the :: word. It works like a regular variable assignment ->, but it calls the object it refers to instead of pushing it to the stack. So you can do what we did above:

{ 1 + } :: increment
## ...
3 increment

Digression: Point-Free Style

You may have heard this phrase used before, probably in relation to Haskell. But it is very relevant to Fith as well. In an applicative language like Python, functions have explicitly named arguments:

def mul_plus_one(a, b):
    return (a * b) + 1

Whereas in Fith, such a function would be idiomatically defined as:

: mul_plus_one ( a b -- a*b+1 ) * 1 + ;

The only mention of arguments is in the stack effect. This is point-free style: not explicitly naming your operands, instead defining functions only in terms of other functions. If you want to learn more about this kind of thing, the Haskell wiki has some interesting information.

In Fith, it is idiomatic to write pointfree functions. In Python, you'd implement the GCD function something like this:

def gcd(a, b):
    while b:
        a, b = b, a % b
    return abs(a)

Note that it's full of variable references. This is Python's way, and that's okay. It works for Python. But if we try to replicate that in Fith, it's ugly and confusing:

: gcd ( a b -- gcd ) -> b -> a { b } { a b mod b -> a -> b } while a abs ;

Eugh. The body of that while loop is frightening. Here's what an idiomatic GCD function looks like:

: gcd ( a b -- gcd ) { dup } { tuck mod } while drop abs ;

Not a single variable needed, and yet it makes more sense; it's also more concise.

Clone this wiki locally