2011-09-08 50 views
4

以下内容返回True(因为2147483647是素数)。为什么Haskell在扩展时抱怨ambigous类型?

length [f | f <- [2..(floor(sqrt 2147483647))], 2147483647 `mod` f == 0 ] == 0 

为什么它不起作用,当我试图扩展它如下?

Prelude> [n | n <- [2..], length [f | f <- [2..(floor(sqrt n))], n `mod` f == 0 ] == 0 ] 

<interactive>:1:39: 
    Ambiguous type variable `t' in the constraints: 
     `RealFrac t' arising from a use of `floor' at <interactive>:1:39-51 
     `Integral t' arising from a use of `mod' at <interactive>:1:56-64 
     `Floating t' arising from a use of `sqrt' at <interactive>:1:45-50 
    Probable fix: add a type signature that fixes these type variable(s) 

虽然我不明白,为什么RealFrac会因使用floor而产生?我认为地板采用了RealFracs并制作了Integrals?再加上它没有抱怨上面的例子,我只输入更多的整数,就像我那样。

Prelude> :t floor 
floor :: (RealFrac a, Integral b) => a -> b 

回答

10

让我们稍微未混淆这样的:

Prelude> (\x -> x `mod` (floor . sqrt) x) 2 

<interactive>:1:24: 
    Ambiguous type variable `b' in the constraints: 
     `Floating b' arising from a use of `sqrt' at <interactive>:1:24-27 
     `Integral b' arising from a use of `mod' at <interactive>:1:7-30 
     `RealFrac b' arising from a use of `floor' at <interactive>:1:16-20 
    Probable fix: add a type signature that fixes these type variable(s) 

您使用的n价值为float,它传递给sqrtfloor。然后,您将该结果用作int,并将结果传递给mod。编译器不能为所有这些实例命名一个类型。

它在你的第一个例子,换句话说

Prelude> 2 `mod` (floor . sqrt) 2 
0 

的原因是因为你使用两个不同的数字文字。一个可以是一个int,一个可以是一个浮点数。如果两者使用相同的值,则需要拨打fromIntegral将int转换为浮点数。

您可以通过添加一个类型签名,改变[2..][2..] :: [Integer]得到一个不同的错误信息:

No instance for (RealFrac Integer) 
    arising from a use of `floor' at <interactive>:1:52-64 
No instance for (Floating Integer) 
    arising from a use of `sqrt' at <interactive>:1:58-63 

这可能让你使用n作为两种不同类型的值更清楚。

-1

正如下面CA麦肯指出,我的答案是不正确的:-)

据我所看到的,那是因为你生产的列表可以由自Floating任何实例的sqrt类型签名

sqrt :: Floating a => a -> a 

通过precomposing sqrtfromIntegral :: (Integral a, Num b) => a -> b,你得到期望的结果:

Prelude> take 10 $ [n | n <- [2..], length [f | f <- [2..(floor(sqrt (fromIntegral n)))], n `mod` f == 0 ] == 0 ] 
[2,3,5,7,11,13,17,19,23,29] 
+2

Haskell的类型默认机制通常会处理这种歧义 - 例如,“Floating”的任何实例通常默认为“Double”。问题中的错误是由于排除默认类型的所有可能选项的约束。 –

相关问题