1

私はこの質問への答えを読んでいました:Haskell:間の違い。(ドット)と$(ドル記号)そして、返事は私を奇妙に感じました...彼+は何を入力していないのですか?そして、私は試しました:

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

おっと...悲しいニュース。しかし、誰かがa-> b-> c ...-> zの方法でそれらを定義したと信じるために、一見恣意的または非常に多くの引数を取ることができる関数を見たと確信しています。それを処理する方法が必要です!私が探しているのは、CLの&restまたは&optionalのようなものです。

4

2 に答える 2

11

確かに、いくつかの型クラスのハッカーを使用して、可変引数加算関数を定義できます

{-# 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標準モジュールでも同じトリックが使用されます。通常、これは 2 つの理由で回避されます。1 つは、提供される型が扱いにくい場合があること、および使用のために明示的な型シグネチャを指定する必要がある場合が多いことです。2 つ目は、これは本当にハックであり、使用する場合はめったに使用しないでください。printf任意の数の引数を取り、ポリモーフィックである必要があるため、単純にリスト list を使用することはできませんが、追加の場合はsum.

1ここでは言語拡張は厳密には必要ありませんが、使用が容易になります (言語拡張がないと、私が示した例で各引数の型を明示的に指定する必要がありますadd (1 :: Integer) (2 :: Integer) :: Integer)。

于 2012-03-03T12:43:18.993 に答える
2

これは構文上のトレードオフです。(一般に) 変数アリティ関数と、関数適用のための優れた Haskell スタイルの構文の両方を同時に持つことはできません。これは、多くの表現があいまいになるためです。

1 または 2 のアリティを許可する関数 foo があると仮定し、次の式を検討します。

foo a b

ここでは引数が 1 つまたは 2 つのバージョンの foo を使用する必要がありますか? これは 2 引数バージョンである可能性がありますが、b に適用された 1 引数バージョンの結果である可能性もあるため、コンパイラが知る方法はありません。

したがって、言語設計者は選択を行う必要があります。

  • Haskell は適切な関数適用構文を選択します (括弧は必要ありません)
  • Lisp は可変アリティ関数を選択します (そしてあいまいさを取り除くために括弧を追加します)
于 2012-03-03T12:22:36.527 に答える