1

我正在阅读这个问题的答案:Haskell:. (点)和$(美元符号)我的回答很奇怪……他的意思是+没有输入?然后我尝试了:

((+) 1)
((+) 1 1)
((+) 1 1 1)

哎呀……不幸的消息。但我确信我看到的函数可以接受看似任意的或大量的参数,以相信有人以 a->b->c...->z 的方式定义了它们。一定有办法处理!我正在寻找的是 CL 中的 &rest 或 &optional 之类的东西。

4

2 回答 2

11

当然,你可以定义一个可变参数加法函数,使用一些类型类黑客:1

{-# LANGUAGE TypeFamilies #-}

class Add r where
    add' :: (Integer -> Integer) -> r

instance Add Integer where
    add' k = k 0

instance (n ~ Integer, Add r) => Add (n -> r) where
    add' k m = add' (\n -> k (m+n))

add :: (Add r) => r
add = add' id

所以:

GHCi> add 1 2 :: Integer
3
GHCi> add 1 2 3 :: Integer
6

Text.Printf标准模块使用相同的技巧。通常避免使用它有两个原因:第一,它提供给您的类型可能难以使用,并且您经常必须为您的使用指定显式类型签名;二,它真的是一个黑客,应该很少使用,如果有的话。printf必须接受任意数量的参数并且是多态的,所以它不能简单地接受一个列表列表,但除了,你可以只使用sum.

1语言扩展在这里不是绝对必要的,但它们使使用更容易(没有它们,您必须在我给出的示例中明确指定每个参数的类型,例如add (1 :: Integer) (2 :: Integer) :: Integer)。

于 2012-03-03T12:43:18.993 回答
2

这是一个语法权衡:你不能(通常)同时拥有可变的arity函数和用于函数应用的漂亮的Haskell风格的语法。这是因为它会使许多表达模棱两可。

假设您有一个函数 foo 允许 1 或 2 的元数,并考虑以下表达式:

foo a b

这里应该使用 foo 的 1 或 2 参数版本吗?编译器无法知道,因为它可能是 2 参数版本,但它同样可能是应用于 b 的 1 参数版本的结果。

因此语言设计者需要做出选择。

  • Haskell 选择了不错的函数应用程序语法(不需要括号)
  • Lisp 选择了可变的 arity 函数(并添加括号以消除歧义)
于 2012-03-03T12:22:36.527 回答