^
Haskell Prelude が累乗のための 2 つの別個の関数 (つまりと)を定義している理由を誰か教えてもらえますか**
? 型システムはこの種の重複を排除するものだと思っていました。
Prelude> 2^2
4
Prelude> 4**0.5
2.0
^
Haskell Prelude が累乗のための 2 つの別個の関数 (つまりと)を定義している理由を誰か教えてもらえますか**
? 型システムはこの種の重複を排除するものだと思っていました。
Prelude> 2^2
4
Prelude> 4**0.5
2.0
実際には、 、 、 の 3 つの累乗演算子が(^)
あり(^^)
ます(**)
。^
は非負の整数累乗、^^
は整数累乗、**
は浮動小数点累乗です。
(^) :: (Num a, Integral b) => a -> b -> a
(^^) :: (Fractional a, Integral b) => a -> b -> a
(**) :: Floating a => a -> a -> a
その理由は、型の安全性です。数値演算の結果は、通常、入力引数と同じ型になります。Int
ただし、 anを浮動小数点数に累乗して、 type の結果を取得することはできませんInt
。したがって、型システムはこれを行うことを防ぎます:(1::Int) ** 0.5
型エラーを生成します。についても同様です(1::Int) ^^ (-1)
。
これを別の言い方をすると、Num
型は で閉じられます^
(乗法逆数を持つ必要はありません)、Fractional
型は で閉じられ^^
、Floating
型は で閉じられ**
ます。のFractional
インスタンスInt
がないため、負のべき乗にすることはできません。
理想的には、 の 2 番目の引数は^
非負になるように静的に制約されます (現在、1 ^ (-2)
実行時例外がスローされます)。しかし、 には自然数の型はありませんPrelude
。
Haskell の型システムは、3 つの指数演算子を 1 つとして表現できるほど強力ではありません。あなたが本当に欲しいのは次のようなものです:
class Exp a b where (^) :: a -> b -> a
instance (Num a, Integral b) => Exp a b where ... -- current ^
instance (Fractional a, Integral b) => Exp a b where ... -- current ^^
instance (Floating a, Floating b) => Exp a b where ... -- current **
マルチパラメータ型クラス拡張をオンにしても、これは実際には機能しません。インスタンスの選択は、Haskell が現在許可しているよりも賢くする必要があるためです。
2 つの演算子を定義するのではなく、3 つの演算子を定義します。レポートから:
引数が 2 つのべき乗演算は 3 つあります。(
^
) は任意の数を非負の整数乗に累乗し、(^^
) 小数を任意の整数乗に累乗し、(**
) は 2 つの浮動小数点引数を取ります。x^0
またはの値は、ゼロを含むx^^0
任意の に対して 1 です。未定義です。x
0**y
これは、3 つの異なるアルゴリズムがあり、そのうちの 2 つは正確な結果 (^
および^^
) を**
提供し、近似的な結果を提供することを意味します。使用する演算子を選択することで、呼び出すアルゴリズムを選択できます。
^
では、2 番目の引数が である必要がありIntegral
ます。私が間違っていなければ、整数指数で作業していることを知っていれば、実装はより効率的になります。また、 のようなものが必要な場合2 ^ (1.234)
、基数が整数 2 であっても、結果は明らかに分数になります。累乗関数に出入りする型をより厳密に制御できるように、より多くのオプションがあります。
Haskell の型システムは、C、Python、Lisp などの他の型システムと同じ目標を持っていません。ダックタイピングは、(ほぼ) Haskell の考え方とは正反対です。