6

uncurryGHCiの機能で遊んでいたのですが、なかなか手に入らないものを見つけました。関数に適用uncurryし、(+)それを以下のコードのように変数にバインドすると、コンパイラーはその型が特定のものであると推測しますInteger

Prelude> let add = uncurry (+)
Prelude> :t add
add :: (Integer, Integer) -> Integer

ただし、次の式のタイプを尋ねると、正しい結果が得られます(私が期待するもの)。

Prelude> :t uncurry (+)
uncurry (+) :: (Num a) => (a, a) -> a

何が原因でしょうか?それはGHCiに特有ですか?

同じことが。にも当てはまりますlet add' = (+)

注:コンパイルされたファイルを使用してそれを再現することはできませんでした

4

2 に答える 2

21

これはghciとは何の関係もありません。これは、イライラする単相制限です。次のファイルをコンパイルしようとした場合:

add = uncurry (+)
main = do
    print $ add (1,2 :: Int)
    print $ add (1,2 :: Double)

エラーが発生します。展開する場合:

main = do
    print $ uncurry (+) (1,2 :: Int)
    print $ uncurry (+) (1,2 :: Double)

予想通り、すべてが順調です。単相性の制限は、「値のように見える」(つまり、equalsの左側に引数なしで定義された)型クラスの多形性を作成することを拒否します。これは、通常発生するキャッシングを無効にするためです。例えば。

foo :: Integer
foo = expensive computation

bar :: (Num a) => a
bar = expensive computation

fooは一度だけ計算されることが保証されていますが(少なくともGHCでは)、bar言及されるたびに計算されます。単相制限は、それがあなたが望んでいたように見えるときに前者をデフォルトにすることによって、後者の場合からあなたを救おうとします。

関数を1回だけ(または常に同じタイプで)使用する場合、型推論が適切な型を推論します。その場合、ghciはもっと早く推測することで少し違うことをしています。しかし、2つの異なるタイプでそれを使用すると、何が起こっているかがわかります。

疑わしい場合は、型署名を使用してください(またはで惨めなものをオフにしてください{-# LANGUAGE NoMonomorphismRestriction #-})。

于 2011-02-15T04:24:49.200 に答える
4

ghciを使用した拡張デフォルトルールには魔法が含まれています。基本的に、特に、Num制約はデフォルトでIntegerに、Floating制約はDoubleに設定されます。そうしないと、エラーが発生します(この場合、悪の単相制限が原因です)。

于 2011-02-15T01:16:56.810 に答える