Haskellが単相性の制限なしに繰り返し評価を避けることができないのはなぜですか?


14

先日learnyouahaskellを終えたばかりで、Haskell Wikiで説明されているように、単相性制限の意味を理解しようとしていました。MRが繰り返し評価を防ぐ方法を理解していると思いますが、なぜこれらの繰り返し評価がはるかに簡単な手段で回避できないのかを理解できません。

私が念頭に置いている特定の例は、wikiで使用されているものです。

f xs = (len,len)
  where
    len = genericLength xs

where genericLengthはタイプNum a => [b] -> aです。

明らかに、それは同じ引数を持つ同じ関数なのでgenericLength xs、評価するために一度だけ計算する必要があり(len,len)ます。そして、それをf知るために呼び出しを見る必要はありません。では、なぜHaskellはMRのようなルールを導入せずにこの最適化を行えないのでしょうか?

そのwikiページの議論Numは、具体的な型ではなく型クラスであるという事実と関係があると言っていますが、それでも、コンパイル時に純粋な関数が同じ値を返すことは明らかではありません-したがって、同じ具体的なタイプのNum-同じ引数を2回与えたとき?

回答:


11

ポリモーフィックであるため、同じ引数を持ち、同じ関数名ですが、潜在的に異なる戻り値の型と実装です。つまり、(Int, MyWeirdCustomNumType)戻り型を期待するコンテキストで呼び出された場合、(+)in の実装はin の実装とIntは完全に異なるため、2回評価する必要が(+)ありMyWeirdCustomNumTypeます。ある時点で物理的に異なるコードを実行する必要があります。

それNumが型クラスであることが重要な理由です。これは、異なるタイプに対して異なる実装があることを意味します。またf、ライブラリ内にある場合、コンパイル時に返される必要がある型のすべての組み合わせを認識しないことも意味します。

そのため、f使用する戻り値の型を知るために、呼び出しを確認する必要があります。ほとんどの場合、それらは同じであると予想されるため、デフォルトでは単相性制限を設定しています。あなたがそうしないまれな機会のためにそれをオフにすることができます。実際には、プログラマーはこの種の状況を型推論に任せる傾向はありません。


私は可能性を考えていませんでしたf [] :: (Int, Float)。今では完全に理にかなっています。ありがとうございました。
Ixrec

1
It's the same function name, with the same arguments, but potentially different return types and implementations, because it's polymorphic.それを見るより良い方法は、typeclassインスタンスが事実上追加の引数でgenericLengthあり、コンパイラが両方の呼び出しで同じ引数であると確信していないことだと思います。
ドーバル

簡単な質問。MonomorphismRestrictionがオフになっているが、後であなたが次のようなa = uncurry (==) $ f [1, 2, 3]ことをした場合、[1, 2, 3]1回の長さのみをチェックするようにその呼び出しサイトを最適化できますか?もしそうなら、私は本当に単相性の制限が実際にあなたを買っているものに関して混乱しています。
セミコロン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.