Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to implement auto-currying to the Lisp-family languages?

That is, when you call a function with >1 arity with only one argument, it should, instead of displaying an error, curry that argument and return the resulting function with decreased arity. Is this possible to do using Lisp's macros?

like image 358
MaiaVictor Avatar asked Jun 27 '12 03:06

MaiaVictor


People also ask

Does lisp have currying?

Above does not work in Lisp, because it has variadic function arguments and no automatic currying. One would always need to explicitly write that (+ 1) should not return 1, but the function 1+. In some functional programming languages it works, because + with one argument returns a one argument function.

How is currying implemented?

Currying is another concept in functional programming. It goes as follow: when a function expects several arguments, we break it down into successive chained functions that each take a single argument. We reduce the arity of each function to one ( arity is the arguments length of a function ).

What is currying in scheme?

Currying is a functional programming tech-nique that takes a function of N arguments and produces a related one where some of the arguments are fixed. In Scheme.


3 Answers

It's possible, but not easy if you want a useful result.

  • If you want a language that always does simple currying, then the implementation is easy. You just convert every application of more than one input to a nested application, and the same for functions of more than one argument. With Racket's language facilities, this is a very simple exercise. (In other lisps you can get a similar effect by some macro around the code where you want to use it.)

    (Incidentally, I have a language on top of Racket that does just this. It gets the full cuteness of auto-curried languages, but it's not intended to be practical.)

    However, it's not too useful since it only works for functions of one argument. You could make it useful with some hacking, for example, treat the rest of the lisp system around your language as a foreign language and provide forms to use it. Another alternative is to provide your language with arity information about the surrounding lisp's functions. Either of these require much more work.

  • Another option is to just check every application. In other words, you turn every

    (f x y z)
    

    into code that checks the arity of f and will create a closure if there are not enough arguments. This is not too hard in itself, but it will lead to a significant overhead price. You could try to use a similar trick of some information about arities of functions that you'd use in the macro level to know where such closures should be created -- but that's difficult in essentially the same way.

But there is a much more serious problem, at the highlevel of what you want to do. The thing is that variable-arity functions just don't play well with automatic currying. For example, take an expression like:

(+ 1 2 3)

How would you decide if this should be called as is, or whether it should be translated to ((+ 1 2) 3)? It seems like there's an easy answer here, but what about this? (translate to your favorite lisp dialect)

(define foo (lambda xs (lambda ys (list xs ys))))

In this case you can split a (foo 1 2 3) in a number of ways. Yet another issue is what do you do with something like:

(list +)

Here you have + as an expression, but you could decide that this is the same as applying it on zero inputs which fits +s arity, but then how do you write an expression that evaluates to the addition function? (Sidenote: ML and Haskell "solves" this by not having nullary functions...)

Some of these issues can be resolved by deciding that each "real" application must have parens for it, so a + by itself will never be applied. But that loses much of the cuteness of having an auto-curried language, and you still have problems to solve...

like image 76
Eli Barzilay Avatar answered Oct 01 '22 14:10

Eli Barzilay


In Scheme it's possible to curry a function using the curry procedure:

(define (add x y)
  (+ x y))

(add 1 2)           ; non-curried procedure call
(curry add)         ; curried procedure, expects two arguments
((curry add) 1)     ; curried procedure, expects one argument
(((curry add) 1) 2) ; curried procedure call

From Racket's documentation:

[curry] returns a procedure that is a curried version of proc. When the resulting procedure is first applied, unless it is given the maximum number of arguments that it can accept, the result is a procedure to accept additional arguments.

You could easily implement a macro which automatically uses curry when defining new procedures, something like this:

(define-syntax define-curried
    (syntax-rules ()
      ((_ (f . a) body ...)
       (define f (curry (lambda a (begin body ...)))))))

Now the following definition of add will be curried:

(define-curried (add a b)
  (+ a b))

add
> #<procedure:curried>

(add 1)
> #<procedure:curried>

((add 1) 2)
> 3

(add 1 2)
> 3
like image 13
Óscar López Avatar answered Oct 01 '22 14:10

Óscar López


The short answer is yes, though not easily.

you could implament this as a macro that wrapped every call in partial, though only in limited context. Clojure has some features that would make this rather difficult such as variable arity functions and dynamit calls. Clojure lacks a formal type system to concretely decide when the call can have no more arguments and should actually be called.

like image 2
Arthur Ulfeldt Avatar answered Oct 01 '22 14:10

Arthur Ulfeldt