14

質問1

こんにちは、WinGHCi で意図的に次の間違ったコードを実行した場合:

3 4

次に、表示されるエラーメッセージは

<interactive>:1:1:
    No instance for (Num (a0 -> t0))
      arising from the literal `3'
    Possible fix: add an instance declaration for (Num (a0 -> t0))
    In the expression: 3
    In the expression: 3 4
    In an equation for `it': it = 3 4

とはNo instance for (Num (a0 -> t0))どういう意味ですか?

質問2

次のコードはなぜですか:

(+) 2 3 4
<interactive>:1:7:
    No instance for (Num (a0 -> t0))
      arising from the literal `3'
    Possible fix: add an instance declaration for (Num (a0 -> t0))
    In the second argument of `(+)', namely `3'
    In the expression: (+) 2 3 4
    In an equation for `it': it = (+) 2 3 4

2 番目のコードとはわずかに異なるエラーが発生します。

2+3 4
<interactive>:1:3:
    No instance for (Num (a1 -> a0))
      arising from the literal `3'
    Possible fix: add an instance declaration for (Num (a1 -> a0))
    In the expression: 3
    In the second argument of `(+)', namely `3 4'
    In the expression: 2 + 3 4

つまり、最初のコード部分にNo instance for (Num (a0 -> t0))は、2 番目のコード部分と同じように がありますNo instance for (Num (a1 -> a0))


【イーヒルドへの対応】

(質問は回答コメントから移動しました):

1) 後者の 2 つの表現が異なることは理解していますが、通訳者が(Num (a0 -> t0))前者と(Num(a1 -> a0))後者を選択する理由を理解する必要はないということですか。

2)こんにちは、前者で「関数の Num インスタンスはありません」と言うとき、どういう意味ですか? 申し訳ありませんが、インスタンスの概念が何であるかが明確ではありません。さらに、好奇心から、インスタンス メソッドを使用して、インタプリタにとしてNum (a -> b)解釈するように指示できますか?3 44 modulo 3

4

2 に答える 2

16

私の意図は、もう少し説明して ehird の答えを補完することです。式を書いたとき

3 4

3次に、Haskell インタープリターは、関数を何にでも適用しようとしていると考えます4。Haskell が3関数として解釈するには、関数を呼び出す必要があります。

fromInteger :: Integer -> (a -> b)

a -> binteger から関数 (つまり、 type の何か) を取得するため3。現在、署名を持つように型クラスfromIntegerで定義されていますNum

instance Num x where
    fromInteger :: Integer -> x

つまり、型をクラスxのインスタンスにするときは、 Haskell に整数リテラルを に変換する方法を伝える実装を与えます。あなたの場合、関数タイプです。では、やりましょう!NumfromIntegerxxa -> b


まず、いくつかのボイラープレート。xHaskellのインスタンスを作成するには、それをandNumのインスタンスにする必要があります。ShowEq

instance Show (a -> b) where show f = "<function>"
instance Eq (a -> b) where f == g = False

3 4ここで、「4 modulo 3」として解釈したいとしましょう。次に、任意の整数を を呼び出す関数として解釈する方法を Haskell に伝える必要がありますmod。さらに、mod整数型 (シグネチャは ) のみを受け入れるため、およびの型も整数mod :: Integral a => a -> a -> a型に制限する必要があります。ab

instance (Integral a, Integral b) => Num (a -> b) where

のインスタンスNumを作成するには(+)、 、(-)(*)およびの実装を提供する必要がありますfromIntegral(実際には、他のいくつかの関数も定義する必要がありますが、今は気にする必要はありません)。

足し算、引き算、掛け算を定義するかなり自然な方法があります (ここからのすべてのコードはインスタンスの一部を形成Numし、インスタンス宣言に対して相対的にインデントする必要があります)。

    f + g = \x -> f x + g x
    f - g = \x -> f x - g x
    f * g = \x -> f x * g x

つまり、2 つの関数fとを追加すると、 と の両方をその引数にg適用する新しい関数が得られ、それらが一緒に追加されます。および適用の結果が整数型である必要があったため、それらの出力を合計することが理にかなっていることがわかります。fgfg

整数を関数として解釈するには、次のように記述できます。

    fromInteger n = \m -> fromIntegral m `mod` fromIntegral n

つまり、 integer がある場合、呼び出されたときに両方の引数が同じ型であることを保証し (両方を呼び出すことによって)、それらを function の引数として使用するnパラメーターの関数を返します。mfromIntegralmod

最後に、Haskell が文句を言うのを止めるためのボイラープレートをもう少し追加します。

    abs f = undefined
    signum f = undefined

これをテストできます。numfun.hs というファイルにコードがあります。Haskell インタープリターを起動し、ファイルをロードします。

Prelude> :l numfun.hs
[1 of 1] Compiling Main             ( numfun.hs, interpreted )
Ok, modules loaded: Main.

これで、いくつかの関数を定義できます。

*Main> let f = (+ 1)
*Main> let g = (* 2)

それらを加算または減算できます。

*Main> (f + g) 3   -- (3+1) + (3*2)
10
*Main> (f - g) 3   -- (3+1) - (3*2)
-2

そして、数値を関数として呼び出すことができます:

*Main> 3 4         -- 4 `mod` 3
1
于 2012-04-30T09:13:18.670 に答える
14

最初のエラーは、のような整数リテラルがインスタンス4を持つ任意のタイプである可能性があるために発生しNumます。つまり4、型がである(Num a) => aため、、、、、などとして機能できます。引数( )に適用したので、コンテキストでは、関数型(つまり、一部と)でなければならないことがわかります。ただし、関数のインスタンスはないため、関数としての使用は無効です。を追加した場合は機能しますが、おそらく必要ありません。IntegerDoubleRational343a0 -> t0a0t0Num3instance Num (a -> b)

後者に関しては、2つのエラーメッセージは同等です。GHCによって生成された名前には特別な意味はありません。文字は通常、使用している関数の型の型変数から派生し、数字は明確にするために追加されます。この場合、2番目の式は(+) 2 (3 4)(関数適用はどの中置演算子よりも緊密にバインドされるため)と同等であり、最初のコードとはまったく同じではありません。

于 2012-04-29T20:14:55.263 に答える