13

次の Haskell 関数を検討してください。

sign a
  | a < 0 = (-1)
  | a > 0 = 1
  | otherwise = 0

これをghciにロードすると、次のようになると予想され:t signました。

sign :: (Num a, Ord a) => a -> Integer

代わりに、次のように推測しました。

*Main> :t sign
sign :: (Num a1, Num a, Ord a1) => a1 -> a

同様に、integer の型を尋ねると、5期待Integerしたのですが、代わりに得られました。

*Main> :t 5
5 :: Num a => a

Haskell の型について、私が理解していないことがあります。問題は、戻り値の型について知っているのsignは、それが型クラスのインスタンスであるということだけである場合、Numその戻り値をこの関数に渡すことができないはずです。

double :: Integer -> Integer
double x = x * 2

つまり、私のdouble関数には、 のIntegerインスタンスだけでなく、 が必要ですNum

それでも、以下は問題なく機能します。

*Main> double (sign 5.5)
2

Haskell の型システムについて誤解しているのは何ですか?

4

3 に答える 3

19

問題は、「sign」の戻り値の型について知っているのは、それが型クラスのインスタンスであるということだけである場合、Numその戻り値をこの関数に渡すことができないはずです。

そうですね、それだけだと に渡せませんねdouble

でもタイプは

sign :: (Num a1, Num a, Ord a1) => a1 -> a

の結果の型は、sign呼び出し元が 要求する型であることを意味します。型シグネチャの型変数は、Java インターフェイスなどのように、存在論的ではなく (暗黙的に)普遍的に量化されます。Num

signのインスタンスであるという制限に従って、任意の型の戻り値を生成できます。戻り値の型はNum、呼び出しコンテキストによって決まります。

呼び出し元が を必要とする場合はInteger、それを取得します。が必要な場合Doubleも問題ありません。

最初に言及するのを忘れました:

同様に、整数 5 の型を尋ねると、「整数」と予想されましたが、代わりに得られました。

    *Main> :t 5
    5 :: Num a => a

数値リテラルは多相的であり、整数リテラルは を表しfromInteger value、小数リテラルは を表しfromRational valueます。

于 2013-03-16T10:58:26.600 に答える
10

@DanielFischerの答えを少し明確にしたかっただけです。型シグネチャのようなf :: Num b => a -> b手段は、 typeclass の任意のfインスタンスを返すことができます。が呼び出されると、Haskell はコンテキスト (呼び出し元の型シグネチャ) を使用して の具体的な型を決定します。Numfb

さらに、Haskell の数値リテラルは、このタイプのポリモーフィズムの例です。:t 5それがあなたに与えた理由ですNum a => a。シンボルは、整数だけでなく、任意の5タイプの数値として機能できます。表示されるコンテキストによって、どちらになるかが決まります。

于 2013-03-16T11:20:38.217 に答える
7

Haskell では、関数が型を返す場合、それは呼び出し元が関数ではなく、型を選択できることxを意味します。むしろ、関数は可能なすべての型を返すことができなければなりません。x

signを含むあらゆるタイプのデータを返すことができますIntegerdouble関数は を必要とするのでInteger、それで問題ありませんsign。それを返すことができます。

あなたが気づいていないかもしれないパズルの別の部分: Java では、2has typeint2.0has type double. しかし、Haskell では、2type を持っています。Num x => xつまり、可能な任意の数値 typeです。(同様の取引である2.0typeもあります。)Fractional x => x

于 2013-03-16T11:20:21.010 に答える