Haskell-style Partial Application

Discussion of Common Lisp
Post Reply
trillioneyes
Posts: 8
Joined: Sat Nov 20, 2010 10:00 pm

Haskell-style Partial Application

Post by trillioneyes » Sun Nov 21, 2010 11:58 am

Okay, I've been using Lisp for a few months now, and I love the language, but recently I tried Haskell and I really like some of the features. I don't think I'll necessarily need the type system, but I really like the curried functions, because it makes mapping very easy. So, I decided I'd write a reader macro to implement Haskell-style partial application.

There is a long but not especially relevant story associated with this; more to the point, though, it ends with a system that works for &optional parameters but fails for &rest. (&key is not supported yet, but I don't think it will be very hard.) This would be semi-acceptable as a start, except that my initial reason for undertaking this was so that I could write (for example) "[+ 10]" instead of "(lambda (x) (+ x 10))", and as most of you probably know, #'+ accepts &rest arguments. I have a plan for adding this, but it involves a list that is two levels of backquote deeper than the surrounding list. Specifically, I can almost write

Code: Select all

`(lambda ,(curry-lambdalist full-arglist num-supplied-args)
    `(funcall ,fn ,@(fetch-required) ,@(fetch-optional) ,@,(fetch-rest)))
But this gives a form that evaluates to the form I want (which is to say, the form that the macroexpander should return, which should itself evaluate to an anonymous function), and if I remember correctly it's bad style to call eval explicitly. Are macroexpanders different, or should I rewrite this so it's not an issue? (If the latter, I'll probably need a complete rewrite. =/)

(Also, it seems moderately likely that some explanation is needed for the functions and variables I've defined. Informally, they do what their names say; more precisely, curry-lambdalist transforms a function's lambda list into a lambda list that has already accepted num-supplied-args arguments and handles &rest and &optional correctly; the fetch-* things take an arglist (for clarity, not shown) and return a list of the symbols representing the required, optional, and rest arguments; and fn is the function that was called at the toplevel.)

ramarren
Posts: 613
Joined: Sun Jun 29, 2008 4:02 am
Location: Warsaw, Poland
Contact:

Re: Haskell-style Partial Application

Post by ramarren » Sun Nov 21, 2010 2:59 pm

It is not exactly clear to me what you have done. Partial application in CL is usually approached either by using basic higher order functions (like CURRY and RCURRY in Alexandria), or, although this is quite rarely used in practice, through read macros, like in curly, or a basic lambda read macro, like subcomponent in arnesi or iterate.

As far as I know none of these approaches requires manipulating the lambda list on a level where knowing what kind of arguments the applied function is required. Do note that unlike some languages in CL a function deals with it's own arguments, and the caller just passes an argument list. Which means that for partial application the generated lambda needs only to take a &rest argument, append the curried arguments to the &rest list and APPLY the function to the result. The code in Alexandria is somewhat more complex due to optimization needs and handling multiple-value returning functions, but that is the idea.

trillioneyes
Posts: 8
Joined: Sat Nov 20, 2010 10:00 pm

Re: Haskell-style Partial Application

Post by trillioneyes » Mon Nov 22, 2010 10:54 pm

Hm, thanks. I thought of using &rest, but for some reason I dismissed it as not feasible (though I was planning on using it to accept keyword arguments, and only keyword arguments). Also, alexandria:curry seems to be exactly what I wanted for my macroexpander; I'll have to look at the source for that.

Post Reply