100

^Haskell Prelude が累乗のための 2 つの別個の関数 (つまりと)を定義している理由を誰か教えてもらえますか**? 型システムはこの種の重複を排除するものだと思っていました。

Prelude> 2^2
4
Prelude> 4**0.5
2.0
4

4 に答える 4

138

実際には、 、 、 の 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

于 2011-06-19T04:54:01.620 に答える
34

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 が現在許可しているよりも賢くする必要があるためです。

于 2011-06-19T14:14:40.350 に答える
11

2 つの演算子を定義するのではなく、3 つの演算子を定義します。レポートから:

引数が 2 つのべき乗演算は 3 つあります。( ^) は任意の数を非負の整数乗に累乗し、( ^^) 小数を任意の整数乗に累乗し、( **) は 2 つの浮動小数点引数を取ります。x^0またはの値は、ゼロを含むx^^0任意の に対して 1 です。未定義です。x0**y

これは、3 つの異なるアルゴリズムがあり、そのうちの 2 つは正確な結果 (^および^^) を**提供し、近似的な結果を提供することを意味します。使用する演算子を選択することで、呼び出すアルゴリズムを選択できます。

于 2011-06-19T04:54:14.050 に答える
4

^では、2 番目の引数が である必要がありIntegralます。私が間違っていなければ、整数指数で作業していることを知っていれば、実装はより効率的になります。また、 のようなものが必要な場合2 ^ (1.234)、基数が整数 2 であっても、結果は明らかに分数になります。累乗関数に出入りする型をより厳密に制御できるように、より多くのオプションがあります。

Haskell の型システムは、C、Python、Lisp などの他の型システムと同じ目標を持っていません。ダックタイピングは、(ほぼ) Haskell の考え方とは正反対です。

于 2011-06-19T04:58:08.577 に答える