ハスケルのべき乗


91

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

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

回答:


130

実際には、3つの指数演算子(^)(^^)あり(**)ます。^は非負の整数指数、^^整数指数、および**浮動小数点指数です。

(^) :: (Num a, Integral b) => a -> b -> a
(^^) :: (Fractional a, Integral b) => a -> b -> a
(**) :: Floating a => a -> a -> a

その理由は型の安全性です。数値演算の結果は通常、入力引数と同じ型です。しかしInt、を浮動小数点のべき乗に上げてtypeの結果を取得することはできませんInt。そして型システムはあなたがこれをするのを防ぎます:(1::Int) ** 0.5型エラーを生成します。同じことがについても言え(1::Int) ^^ (-1)ます。

別の言い方をすると、Num型は閉じられ^ており(乗法的逆数を持つ必要はありません)、Fractional型はで閉じられ^^Floating型はで閉じられてい**ます。のFractionalインスタンスがないのでIntがないため、負の累乗にはできません。

理想的には、の2番目の引数は^静的に負でない値に制約されます(現在、1 ^ (-2)実行時例外がスローされます)。ただし、には自然数の型はありませんPrelude


31

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が現在許可しているよりも賢い必要があるため、マルチパラメータータイプのクラス拡張をオンにしても、これは実際には機能しません。


4
これが実装可能ではないという記述はまだ正しいですか?IIRC、haskellには、マルチパラメータータイプのクラスの2番目のパラメーターが最初のパラメーターによって厳密に決定されるオプションがあります。これ以外に解決できない問題はありますか?
RussellStewart 2014年

2
@singularそれはまだ本当です。最初の引数は2番目の引数を決定しません。たとえば、指数をとの両方にしたいIntとしIntegerます。これら3つのインスタンス宣言を可能にするには、インスタンス解決でバックトラッキングを使用する必要があり、Haskellコンパイラはそれを実装していません。
2014年

7
「タイプのシステムは強力ではありません十分な」引数は、まだ2015年3月の時点で保持しますか?
Erik Kaplun、2015年

3
あなたは確かに私が提案する方法でそれを書くことはできませんが、それをエンコードするいくつかの方法があるかもしれません。
8


10

2つの演算子は定義されていません-3つが定義されています!レポートから:

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

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


4

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

Haskellの型システムには、C、Python、Lispなどの他の型システムと同じ目的はありません。アヒルのタイピングは、(ほぼ)Haskellの考え方とは逆です。


4
Haskellタイプの考え方がアヒルのタイピングの反対であることに私は完全に同意しません。Haskellの型クラスは、アヒルの型付けによく似ています。 class Duck a where quack :: a -> Quackアヒルに何を期待するかを定義し、各インスタンスがアヒルのように動作できるものを指定します。
8

9
@augustssどこから来たのかわかります。しかし、アヒルのタイピングの背後にある非公式のモットーは、「それがアヒルのように見え、アヒルのように振る舞い、そしてアヒルのように鳴く場合、それはアヒルです」です。Haskellでは、のインスタンスが宣言されていない限り、アヒルではありませんDuck
Dan Burton

1
それは本当ですが、それは私がHaskellに期待することです。アヒルが欲しいものは何でも作ることができますが、それについて明示する必要があります。アヒルになることを求めなかったものを間違えたくないのです。
8

Haskellの方法とダックタイピングには、より具体的な違いがあります。はい、どのタイプにもDuckクラスを指定できますが、Duckではありません。それは確かにガタガタする能力がありますが、それでも、具体的には、どのようなタイプでもあります。あなたはまだアヒルのリストを持つことができません。アヒルのリストを受け入れ、さまざまなタイプのクラスのアヒルを混合および照合する関数は機能しません。この点で、Haskellは「アヒルのように鳴るなら、それはアヒルだ」とだけ言うことを許可しません。Haskellでは、アヒルはすべて同じタイプのクワッカーでなければなりません。これは実際にアヒルのタイピングとはかなり異なります。
mmachenry 2016

混合アヒルのリストを作成できますが、Existential Quantificationの拡張が必要です。
Bolpat
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.