2016-12-08 7 views
27

を機能:矛盾挙動は、以下の定義を使用して

lenDigits n = length (show n) 
factorial n = product [1..n] 

私はそのような行動の理由は何次

Prelude> ((lenDigits . factorial) 199) <= 199 
False 
Prelude> (\i -> ((lenDigits . factorial) i) <= i) 199 
True 

を評価しますか?私が見ているように、最初の式はラムダを減らした2番目の式とちょうど同じです。

+5

あなたかもしれないまた、問題の本質に取得し、すべての気まぐれを回避これら二つを比較するような'(id True、id 'a')'は大丈夫ですが、 '(\ f - >(f True、f 'a'))id'はエラーです。 –

+0

@DanielWagnerなぜこれが起こりますか? 'id'は多相ではないのですか? –

+3

はい、実際には、 'id'は多相です。 '\ f - > ...'は多態性を持つことができます。しかし、 '...'の内部では、 'f'自体は多型ではありません! '\ f - >(f True、f 'a')'は既に 'id'を言及していない型エラーです。この制限は、型推論をより簡単にし、ある型を与えることができるすべての用語が最も一般的な型を持つ望ましい特性を保持するために設けられています。 –

答えて

25

最初の式で最初の199Integerの型を持ち、2番目の式はIntです。しかし、第2の表現では、いずれもタイプIntおよびfactorial 199をタイプIntで表すことはできません。

+1

これは単相性の制限に関連していますか? – mnoronha

+14

私はそうは思わない。最初の例では、最初の199はデフォルトの 'Integer'に自由に設定されていますが、' lenDigits'の戻り値と比較されているので、 'Int'として扱われます。 2番目の引数では、同じ理由で 'i'が強制的に 'Int'になるため、199も' Int'になります。 – chepner

+1

@chepnerはい、あなたはまさにそうです! – freestyle

8

ここでは、この質問をステップバイステップで取り上げます。

のは、始めましょう:リテラルHaskell Report ...

によると

((lenDigits . factorial) 199) <= 199 

整数型Integerの適切な値に機能fromIntegerのアプリケーションを表します。私たちの最初の式が実際にあることを意味し

((lenDigits . factorial) (fromInteger (199 :: Integer)) 
    <= (fromInteger (199 :: Integer)) 

自体によって、fromInteger (199 :: Integer)は、ポリモーフィック型のNum a => aを持っています。このタイプは、表現全体の文脈に特化しているかどうかを見なければなりません。その理由が見つからなくなるまで、fromInteger (199 :: Integer)という2つの出現の多型は独立していると仮定してください(Num a => aNum b => b、もしそうなら)。

lenDigitsShow a => a -> Intあり、そしてそう...

(lenDigits . factorial) (fromInteger (199 :: Integer)) 

... <=の左側にIntでなければなりません。 (<=)Ord a => a -> a -> Boolであるとすれば、<=の右側のfromInteger (199 :: Integer)Intである必要があります。式全体は、次いで、以下のようになる。

((lenDigits . factorial) (fromInteger (199 :: Integer)) <= (199 :: Int) 

199は最初のものはまだ多型である、Intに特化したが。他のタイプの注釈がない場合、GHCiで式を使用すると、defaultingはIntegerに特化します。したがって、我々は、最終的に得る:第二の発現の上に今

((lenDigits . factorial) (199 :: Integer)) <= (199 :: Int) 

を:

(\i -> ((lenDigits . factorial) i) <= i) 199 

上記使用されたのと同じ理由により、(lenDigits . factorial) i<=の左側に)Intであるのでi<=の右側にある)もIntです。

((lenDigits . factorial) (199 :: Int)) <= (199 :: Int) 

最初199は今:与える、そうされていることを、私たちは...

GHCi> :t \i -> (lenDigits . factorial) i <= i 
\i -> (lenDigits . factorial) i <= i :: Int -> Bool 

を持っている...ので、intに(これは実際にfromInteger (199 :: Integer)である)、それを専門と199にそれを適用しますIntegerではなくIntです。 factorial (199 :: Int)は、固定サイズIntタイプをオーバーフローし、偽の結果につながります。最初のシナリオと同等のものを得るためにそれを回避する1つの方法は、明示的なfromIntegerを導入することになります。

GHCi> :t \i -> (lenDigits . factorial) i <= fromInteger i 
\i -> (lenDigits . factorial) i <= fromInteger i :: Integer -> Bool 
GHCi> (\i -> (lenDigits . factorial) i <= fromInteger i) 199 
False