Ghciで私が入力できるのはなぜですか?
5.0 * (3 - 1)
> 10.0
しかし、.hsファイルに関数を作成してロードすると、次のようになります。
test :: Float -> Int -> Int -> Float
test a b c = a * (b - c)
エラーが発生しましたか? 「予想される型 'Float'と推定される型 'Int'を一致させることができませんでした。1つの浮動小数点と2つの整数の引数を取り、上記の操作を実行する関数をどのように記述できますか?
私はそれが違いを生むならghci v6.12.1を使用しています...
数値リテラル(Haskellコードで数値を入力するだけ)は、固定型ではありません。それらは多態性です。それらは、具体的な型を持つことを必要とするいくつかのコンテキストで評価される必要があります。
したがって、式5.0 * (3 - 1)
はnotInt
にFloat
を乗算したものです。 _5.0
_はいくつかのFractional
タイプである必要があり、_3
_および_1
_はそれぞれいくつかのNum
タイプです。 _3 - 1
_は、3と1の両方がsameNum
タイプである必要があることを意味しますが、特定の1つに関する制約は(まだ)まだありません。そうです。減算の結果は同じ型です。
_*
_は、両方の引数が同じ型でなければならず、結果も同じ型になることを意味します。 _5.0
_はFractional
型なので、_(3 - 1)
_もそうである必要があります。 _3
_、_1
_、および_(3 - 1)
_はいくつかのNum
タイプでなければならないことはすでに知っていましたが、すべてのFractional
タイプもNum
ですタイプなので、この要件は競合しません。
最終結果は、式5.0 * (3 - 1)
がFractional
である型であり、_5.0
_、_3
_、および_1
_がすべて同じタイプ。 GHCiで_:t
_コマンドを使用すると、これを確認できます。
_Prelude> :t 5.0 * (3 - 1)
5.0 * (3 - 1) :: Fractional a => a
_
しかし、実際にevaluateの式を使用するには、いくつかの具象型に対してそうする必要があります。これを評価して、Float
、Double
、またはその他の特定のFractional
型を必要とする関数に渡すと、Haskellはその型を選択します。特定の型である必要がある他のコンテキストなしで式を評価する場合、Haskellにはいくつかのデフォルトのルールがあり、自動的に1つを選択します(デフォルトのルールが適用されない場合は、あいまいな型の変数に関する型エラーが発生します)。
_Prelude> 5.0 * (3 - 1)
10.0
Prelude> :t it
it :: Double
_
上記では5.0 * (3 - 1)
を評価してから、GHCiが常に評価した最後の値にバインドするmagic it
変数のタイプを尋ねました。これは、式の値が_Fractional a => a
_であることを計算するために、GHCiがデフォルトの_10.0
_タイプをDouble
にデフォルト設定したことを示しています。その評価を行う際には、Double
sを乗算(および減算)するだけで、Double
にInt
を乗算することはありません。
さて、複数の数値literalsを試してみると、タイプが異なる可能性があります。しかし、あなたのtest
関数はリテラルを乗算しているのではなく、特定の既知の型の変数を乗算しています。 Haskellでは、Int
にFloat
を乗算することはできません。これは、_*
_演算子の型が_Num a => a -> a -> a
_であるため、同じ数値型の2つの値を受け取り、そのタイプの結果。 Int
にInt
を乗算してInt
を取得するか、Float
にFloat
を乗算してFloat
。 Int
とFloat
を乗算して_???
_を取得することはできません。
他の言語は、状況によっては、変換関数の呼び出しを暗黙的に挿入することによってのみ、この種の操作をサポートします。 Haskell neverは型間で暗黙的に変換しますが、変換関数があります。それらを呼び出したい場合は、明示的に呼び出す必要があります。これはトリックを行います:
_test :: Float -> Int -> Int -> Float
test a b c = a * fromIntegral (b - c)
_
代わりに以下を試してください。
_test :: Float -> Int -> Int -> Float
test a b c = a * fromIntegral (b - c)
_
なぜこれが機能するのですか?
b
とc
はどちらもInt
sであるため、式_(b - c)
_もInt
です。(*)
_の型シグネチャは_Num a => a -> a -> a
_です。a
の型はFloat
であるため、Haskellは_(a*)
_の型シグネチャを_Float -> Float
_に更新します。(b - c)
_はInt
ではなくFloat
であるため、a * (b - c)
を実行しようとするとHaskellは文句を言うでしょう。fromIntegral
の型シグネチャは_(Integral a, Num b) => a -> b
_です。fromIntegral (b - c)
の型シグネチャは_Num b => b
_です。Float
はtypeclass Num
のインスタンスなので、_(*)
_の型シグネチャは_Num a => a -> a -> a
_であるため、a * fromIntegral (b - c)
を実行できます。test
の型シグネチャからの結果は、Float
と評価されます。これがお役に立てば幸いです。
署名を追加する前のtest
関数はより一般的でした。
> let test a b c = a * (b - c)
> :t test
test :: Num a => a -> a -> a -> a
あなたはそれを制限することができますが、すべてのタイプは同じでなければなりません:
test :: Fractional a => a -> a -> a -> a -- some real types
test :: Integral a => a -> a -> a -> a -- all integer types
test :: Float -> Float -> Float -> Float
test :: Int -> Int -> Int -> Int
test :: Int -> Float -> Float -> Float --wrong
ところで、2
はInt
ではなく、0.2
はFloat
ではありません。gchi
に質問してみましょう。
> :t 2
2 :: Num a => a
> :t 0.2
0.2 :: Fractional a => a
浮動小数点数を乗算する前に、整数にfromIntegral
を使用する必要があります。
http://www.haskell.org/haskellwiki/Converting_numbers
GHCIでは、使用するまで数値は浮動小数点数または整数とは見なされません。 (例:実行時)。これは、REPLスタイルの開発に適しています。
コンパイラ本体では、 自動強制はありません。それそれ 乗算は、2つの値が乗算をサポートする型クラスに属している必要があることを前提としています。例:intの乗算、またはfloatの乗算。他の明示的に型指定された関数を使用しなかったため、intを想定しました。その仮定は(オプションの)型シグネチャによって異なります。