Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell-style sections in Common Lisp

In Haskell, if I have a lambda that looks like the following

(\x -> doStuff x y)

where y is from the surrounding scope, I could section it and turn it into

(`doStuff` y)

which is shorter and more concise (and one of the things I love the most about Haskell).

Now, in Common Lisp I would write the equivalent code as

(lambda (x) (do-stuff x y))

And this is actually a very common thing for me to be writing, but I feel even that tiny bit of boilerplate bothers me somewhat, so I wonder if there is a way to get something like the Haskell-style sections in Common Lisp?

like image 867
jaymmer - Reinstate Monica Avatar asked Mar 22 '13 10:03

jaymmer - Reinstate Monica


1 Answers

Unless you are more experienced, I would propose that you learn to write Lisp in Lisp, not how to write Haskell in Lisp. The latter is not a good idea. Haskell works very different.

Lisp does not do any 'currying' (or schönfinkeling ;-) ).

You can write it as:

CL-USER 5 > (defun curry (fn arg) (lambda (&rest args) (apply fn arg args))) 
CURRY

CL-USER 6 > (mapcar (curry #'expt 2) '(2 3 4 5 6))
(4 8 16 32 64)

It costs a bit efficiency that way, though.

CL-USER 7 > (mapcar (lambda (base) (expt base 2)) '(2 3 4 5 6))
(4 8 16 32 64)

I personally prefer the latter, because I have a real readable name for the variable. This helps in a debugger, where I see then a backtrace. Tools like these are probably more important in Lisp, than in Haskell.

CL-USER 12 > (mapcar (lambda (base) (expt base 2)) '(2 3 "four" 5 6))

error. Let's look at the backtrace:

CL-USER 12 : 1 > :bb
...

Condition: In EXPT of ("four" 2) arguments should be of type NUMBER.

Call to SYSTEM::ARGS-TO-BINARY-ARITHMETIC-FN-NOT-OF-TYPE {offset 189}
  SYSTEM::FN-NAME : EXPT
  SYSTEM::ARG1    : "four"
  SYSTEM::ARG2    : 2
  TYPE  {Closing} : NUMBER

Interpreted call to (SUBFUNCTION :ANONYMOUS SYSTEM::ANONYMOUS-LAMBDA):
  BASE : "four"

Now I can see that the thing has a name. I was passing the string "four" to the function with a variable named base.

Interactive development with REPL and debugging tools is common. Best prepare the code to be useful for this development style. Common Lisp is not optimized to provide full program compilers with extensive type checking - like in Haskell.

One of the main problems of Lisp is that it can be very hard to find out what a piece of code really does. The default (strict functional programs with prefix syntax) is relatively easy to understand. But there are many possibilities to change the meaning of code in Lisp (macros, read macros, symbol macros, the Meta Object protocol, advising, ...).

First rule: if you are writing basic Lisp code, stick with the basic syntactic and semantic possibilities. Write defensively. Expect that someone else needs to understand the code. For that the code should be readable, easy to understand, use common idioms and it should be debuggable.

In Haskell many people with math background want to write code in a very compact way with a high level of abstraction. You can do that in Lisp, too. But for ordinary code I would not go that route and for larger pieces of code, Lisp often uses other mechanisms (code transformations via macros, ...).

like image 148
Rainer Joswig Avatar answered Oct 11 '22 16:10

Rainer Joswig