You may remember the LOGO programming language from the old days of Turtle Graphics. If you are like me, you probably remember drawing polygons and stars by typing a command like:
repeat 5 [forward 100 right 72]
This draws a pentagon, and with different numbers plugged in the 3 different places, you can get a infinite variation of shapes.
But it turns out LOGO is more than just forward, turn left, turn right, and repeat - it actually is a pretty powerful language having its roots in LISP.
Much like LISP, the list data type is central to the language. As an example, let's write a sumlist function which just sums the numbers in a list. A list is written like
[1 2 3 4]
So calling the function looks like
print sumlist [1 2 3 4]
This should print 10 as the result.
Like LISP again, LOGO uses linked lists, so the most basic way to iterate a list would be to use tail recursion. We can write sumlist like this
to sumlist :list
ifelse equal? 0 (count :list)
[0]
[(first :list) + (sumlist butfirst :list)]
end
Declaring a function has a nice down-to-earth syntax
to func :param1 :param2 ... statement1 statement2 ... end
The ifelse function simulates an if-else statement, taking 3 parameters, the test condition, a statement block to execute for true and another for false. So here we are saying if the list is empty, return zero, otherwise return the first element of the list plus the sum of the rest(butfirst) of the list. Notice that the statement blocks passed as the second and third arguments to the ifelse function are nothing more than lists. Lists, in addition to acting as literal lists of element, also double as lazily evaluated statement blocks.
Writing recursive functions is usually kinda tedious like the sumlist function that we wrote above, but if you knew a little about functional programming, you know that you can use foldr or reduce to simplify your code. Well, you can do that in LOGO too
to sumlist :list (reduce "sum :list 0) end
Sweet! Now we have a one-liner. You can read up on foldr or reduce if you don't know it - I won't explain it in depth here. Essentially, the reduce function allowed us to refactor our recursive function into a much more succinct form.
Great! But we aren't done yet. There's a yet simpler way to write the function. It turns out that there's already a sum function in UCBLogo - perhaps the most popular implementation of LOGO. It does not act exactly the way we want though. You can sum two numbers together
print sum 1 2
prints 3.
But if you try adding more parameters it'll just ignore them
print sum 1 2 3
still prints 3.
Turns out you can use variable number of parameters, you just have to write it differently
print (sum 1 2 3)
prints 6. This is called the LISP-style call syntax. Notice that a function has a natural arity(number of parameters). In the case of sum the natural arity is 2, but the arity can be changed if you use the LISP-style call syntax. Using the natural arity of the function for lookahead is the reason why LOGO code doesn't have as much parentheses as LISP code. You can write
forward 100 right 45 forward 50 left 80
There is no ambiguity as to what is the correct grouping for this expression because each of the functions forward, right, left take one parameter, and the interpreter uses that information for disambiguation during parsing.
Anyway, I digress. Now, back to the sum function. It turns out we can also call the function using the apply function, much like Javascript's Function.prototype.apply. And so, our final version of sumlist looks like
to sumlist :list apply "sum :list end
Nice! apply takes two arguments: the name of the function to call and the parameter list. We prepend a double quote to sum to make it a string literal to prevent it from being applied as a function.
There's a counterpart for Function.prototype.call in Javascript too, it's called invoke.
print (invoke "sum 1 2 3)
But like Javascript's call() it's also less useful than apply.
Going Further
Joshua Bell wrote a LOGO interpreter in Javascript. That's where you'd go if you want to try out some LOGO right away. Alternatively, download UCBLogo.