可能重复:
为什么在haskell中不允许这样的函数定义?
我是从 Lisp 迁移过来的 Haskell 世界的新手。我正在努力适应 Haskell 完全不同的世界观,而我发现许多新的和令人兴奋的事情之一就是类型系统。作为一个 Lisper,我想我会尝试在 Haskell 中实现一个在 Lisp 世界中非常重要的功能:apply
. 对于那些不知道的人,apply 接受一个函数和一个参数列表,并在这些参数上调用函数。在 Scheme 中,(apply + '(1 2 3))
与调用 相同(+ 1 2 3)
,返回 6。
我的 Haskell 代码如下所示:
apply x [] = x
apply f (x:xs) = apply (f x) xs
但是 Haskell 抱怨说:
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
我想我明白为什么。Apply 的类型需要根据给出的列表的长度而有所不同。给定一个包含 3 个项目的列表,apply 的类型需要是: (a -> a -> a -> b) -> [a] -> b
,但是给定一个包含 6 个项目的列表,apply 的类型需要是: (a -> a -> a -> a -> a -> a -> b) -> [a] -> b
。
我尝试了这个可怕的解决方法:
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]
这行得通,但它几乎不能算作一个apply
函数,因为我不能传递apply
一个普通的函数,我必须使用一个专门编写的函数来使用我的(尴尬的)FnOrDat 抽象。如果我想编写一个添加四个数字的函数,我需要编写
add4 a = Fn (\b -> Fn (\c -> Fn (\d -> Dat (a + b + c + d))))
嗯。
那么 - 我是否遗漏了什么,或者要求一个通用的,apply
基本上就像要求一个可以操作任意长度元组的函数?在 Haskell 的静态类型世界观中是否apply
有意义?