Rotating args in Haskell, partially explained

In the last article I talked a bit about rotating arguments in Haskell. How come we can do that with Haskell and not with most other languages? Well one reader sort of jumped the gun and tried to give the secret away. In fact, they were unhappy that I didn't start off the article explaining the secret to you ... they were afraid I'd lead you astray. You now, up until now I really thought my blog title was self-explanatory ...

Anyway, the secret is that Haskell functions only take one argument. Yes, you heard that correct. Haskell does currying underneath so that it appears to you as if you have a function with multiple arguments. Let's look at a quick example.

In most languages, one would read the following as, foo is a function that takes two arguments of type Int and returns an Int. But in Haskell, it's read as, foo is a function that takes an Int and returns a function that takes an Int and returns an Int.

foo :: Int -> Int -> Int
foo x y = x + y

-- the type signature is equivalent to this type signature

foo :: Int -> (Int -> Int)

The automatic currying enables partial application of functions in ways that I hadn't seen with other languages. To achieve the same result in another language generally requires wrapping it in another lambda. But it's just so pervasive and natural with Haskell that one forgets that it's anything special.

-- goal:  given function foo, create another function that has
--        partially applied foo to the value 7 and map it over
--        a list from 0 to 10.

-- in Lisp
(defun foo (x y)
  (+ x y))

(mapcar #'(lambda (y) (foo 7 y)) (reverse (numbers-up-to 10)))

-- in Ruby
def foo x, y
  x + y

(0..10).map { |y| foo 7, y }

-- in Haskell
foo :: Int -> Int -> Int
foo x y = x + y

map (foo 7) [0..10]

Additional Reading

tags: haskell, lisp, ruby


comments powered by Disqus