3

フォールドを使用して、Haskell の整数の合計の 2 乗をとろうとしています。しかし、GHCi から不可解なエラーが発生します。これが私のワンライナーです:

((^2) . foldl) (+) 0 [1..100]

私がGHCiから得ているものは次のとおりです。

Prelude> ((^2) . foldl) (+) 0 [1..100]

<interactive>:19:3:
    No instance for (Num (b0 -> [b0] -> b0))
      arising from a use of `^'
    Possible fix:
      add an instance declaration for (Num (b0 -> [b0] -> b0))
    In the first argument of `(.)', namely `(^ 2)'
    In the expression: (^ 2) . foldl
    In the expression: ((^ 2) . foldl) (+) 0 [1 .. 100]

問題は、この型宣言に基づいて最後に渡すリストにあると思います。

Prelude> :t ((^2) . foldl) (+) 0 [1..100]
((^2) . foldl) (+) 0 [1..100]
  :: (Enum b, Num b, Num (b -> [b] -> b)) => b

Enumこの関数をデバッグできるように、この型がリストを明示的にキャストする方法を期待している理由について、誰かが私に洞察を与えることができますか? 前もって感謝します。

4

3 に答える 3

9

ええ、これは GHC が生成する最もばかげた、役に立たないエラー メッセージの 1 つです。

最初に、メッセージを無視して、 と のタイプを検討しfoldlます(.)

foldl :: (a -> b -> a) -> a -> [b] -> a
(.) :: (b -> c) -> (a -> b) -> a -> c

(.)最初の引数のみを使用して構成することに注意してください。カリー化のため、「複数の」引数を持つ関数は、実際には別の関数を返す 1 つの引数の関数です。したがって、式で((^2) . foldl)は、の「戻り値の型」はfoldlisa -> [b] -> aであり、これは で構成しようとするもの(^ 2)です。

また、エラー メッセージが馬鹿げているため、構成するためのNumインスタンスがないと文句を言い、インスタンスを追加するよう提案します。a -> [b] -> a(^2) :: Num a => a -> a

あなたが欲しかったのは次のようなものです: ((^2) . foldl (+) 0). とはいえ、ここで(lazy) を使用するのfoldlはおそらく悪い考えです。strict を使用するfoldl'か、組み込みsum関数を使用することをお勧めします。(^2) . sum

また、Enum型で言及されている制約は無関係であり、実際には正しいものですEnum。型クラスは、範囲表記を解釈するために使用される関数を提供します。つまり(Enum b, Num b) => ...bこれは列挙可能な数値型であり、これはまさに式に必要なものです[1 .. 100]

于 2013-04-21T05:39:24.350 に答える
5

正しい書き方は(^2) . foldl (+) 0 :: Num a => [a] -> aor(^2) . foldl (+) 0 $ [1..100] :: (Num a, Enum a) => aです。単独で行う場合は、関数であるの最初の戻り値の型の(^2) . foldl引数を 2 乗しようとします。エラーはこれを宣言します:この種の関数のインスタンスがないため、適切なべき乗関数をディスパッチできません。foldla -> [a] -> aNum(^)

一般に、コンポジション(.)は、単一入力の関数でのみ機能するものと考えてください。タイプはこれを示しています

(.) :: (b -> c) -> (a -> b) -> a -> c

より一般的な用途もありますが、見つけるのは少し難しいです。

したがって、私のソリューションは、foldl構成する前に引数を直接適用するため機能します。これらの引数foldl (+) 0 :: Num a => [a] -> aは、単一の入力引数の関数を作成します。

于 2013-04-21T05:37:35.877 に答える
0

良い答えが与えられましたが、おそらくそれを書く方が簡単です

(^2) $ foldl (+) 0 [1..100]

foldl (+) 0 [1..100]はそれ自体で機能します。これは、foldl がどのように機能するかを理解しようとしている場合に役立ちます。その後、結果が に渡されます(^2)。関数として記述

f list = (^2) $ foldl (+) 0 list

于 2013-04-23T11:55:33.517 に答える