Haskell"申请"?

Ord*_*Ord 20 lisp haskell types polyvariadic

可能重复:
为什么haskell中不允许这样的函数定义?

我是Haskell世界的新手,从Lisp迁移过来.我正在努力适应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
Run Code Online (Sandbox Code Playgroud)

但哈斯克尔抱怨道:

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
Run Code Online (Sandbox Code Playgroud)

而且我认为我理解为什么.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]
Run Code Online (Sandbox Code Playgroud)

这是有效的,但它几乎apply不算是一个函数,因为我不能传递apply一个普通函数,我必须使用一个专门编写的函数来使用我的(笨拙的)FnOrDat抽象.如果我想写一个添加四个数字的函数,我需要写

add4 a = Fn (\b -> Fn (\c -> Fn (\d -> Dat (a + b + c + d))))
Run Code Online (Sandbox Code Playgroud)

EW.

所以 - 我错过了什么,或者是否要求一般用途,apply就像要求一个可以操纵任意长度元组的函数一样?难道apply甚至有意义哈斯克尔的静态类型的世界观?

Don*_*art 11

apply在Haskell中不是很有用,因为你不能给函数赋一个类型.正如你在FnOrDat中看到的那样,你实际上是将一个Lisp语言作为EDSL嵌入到Haskell中以强制通过.

要求一个通用的应用基本上就像要求一个可以操纵一个任意长度的元组的函数?

究竟.您可以为某些有用的类型组合提供类型类实例,但实际上并不需要或使用一般的可变参数apply.


作为旁注,您应该考虑升级到GHC和Haskell平台,而不是过时的Hugs系统,因为您错过了过去10年中开发的大多数库,工具和语言功能.

  • 谢谢!实际上,我在我的"主"电脑上使用GHC.我在其他地方打字,所以我只是用codepad.org来测试我的代码片段.我猜他们用Hugs? (2认同)