Possible Duplicate:
Why is such a function definition not allowed in haskell?
I'm a newcomer to the world of Haskell, migrating over from Lisp. I'm trying to adjust to Haskell's fundamentally different worldview, and one of the many things that I find new and exciting is the type system. Being a Lisper, I thought I would try to implement in Haskell a function which is very important in the Lisp world: apply
. For those who don't know, apply takes a function and a list of arguments, and invokes the function on those arguments. In Scheme, (apply + '(1 2 3))
is the same as invoking (+ 1 2 3)
, and returns 6.
My Haskell code looks something like this:
apply x [] = x
apply f (x:xs) = apply (f x) xs
But Haskell complains:
ERROR line 2 - Type error in function binding
*** Term : apply
*** Type : (b -> a) -> [b] -> a
*** Does not match : a -> [b] -> a
*** Because : unification would give infinite type
And I think that I understand why. Apply's type needs to be different depending on the length of the list it is given. Given a list of, say, 3 items, apply's type would need to be: (a -> a -> a -> b) -> [a] -> b
, but given a list of 6 items, apply's type would need to be: (a -> a -> a -> a -> a -> a -> b) -> [a] -> b
.
I tried this horrendous work-around:
data FnOrDat a b = Dat b | Fn (a -> FnOrDat a b)
apply :: (FnOrDat a b) -> [a] -> (FnOrDat a b)
apply x [] = x
apply (Fn f) (x:xs) = apply (f x) xs
apply (Dat _) _ = error "Cannot apply something which is not a function!"
add a = Fn (\b -> Dat (a + b))
main = putStrLn $ show $ x where Dat x = apply (Fn add) [5,1]
This works, but it hardly counts as an apply
function, because I can't pass apply
a normal function, I have to use one that has been written specifically to use my (awkward) FnOrDat abstraction. If I wanted to write a function that added four numbers, I would need to write
add4 a = Fn (\b -> Fn (\c -> Fn (\d -> Dat (a + b + c + d))))
Ew.
So - am I missing something, or is asking for a general-purpose apply
basically like asking for a function that can manipulate an arbitrary-length tuple? Does apply
even make sense in the statically-typed worldview of Haskell?