我写了一个函数来检查数字是否为素数:
prime n = prime' n 2 (floor (sqrt n))
where prime' n c u | n `mod` c == 0 = False
| c > u = True
| otherwise = prime' n (c+1) u
我无法弄清楚这个函数的类型签名应该是什么。起初我认为应该是这样的:
prime :: Integral a => a -> Bool
但是我在编译时遇到错误,因为sqrt
期望Floating a
而floor
期望RealFrac a
而不是Integral a
。当我删除类型签名时,它会编译,但该函数不起作用:
*Euler> :t prime
prime :: (Integral a, RealFrac a, Floating a) => a -> Bool
*Euler> prime 5
<interactive>:1:0:
Ambiguous type variable `t' in the constraints:
`Floating t' arising from a use of `prime' at <interactive>:1:0-6
`RealFrac t' arising from a use of `prime' at <interactive>:1:0-6
`Integral t' arising from a use of `prime' at <interactive>:1:0-6
Probable fix: add a type signature that fixes these type variable(s)
如何使此功能有效?
答案 0 :(得分:12)
问题是您在sqrt
上使用n
,这会强制n
为浮点数;并且您还在mod
上使用n
,这会强制n为整数。直观地说,通过查看代码,n
应该是一个整数,因此您无法直接在其上调用sqrt
。相反,您可以使用类似fromIntegral
的内容将其从整数转换为另一种数字类型。
prime :: (Integral a) => a -> Bool
prime n = prime' n 2 (floor (sqrt (fromIntegral n)))
where prime' n c u | n `mod` c == 0 = False
| c > u = True
| otherwise = prime' n (c+1) u
答案 1 :(得分:3)
最后一点,其他答案没有涵盖......
*Euler> :t prime
prime :: (Integral a, RealFrac a, Floating a) => a -> Bool
只要prime
是a
,a
的实例,并且Integral
可以采用RealFrac
类型的参数,一次Floating
个课程。
*Euler> prime 5
<interactive>:1:0:
Ambiguous type variable `t' in the constraints:
`Floating t' arising from a use of `prime' at <interactive>:1:0-6
`RealFrac t' arising from a use of `prime' at <interactive>:1:0-6
`Integral t' arising from a use of `prime' at <interactive>:1:0-6
Probable fix: add a type signature that fixes these type variable(s)
然而,当您向prime 5
提出要求时,它会抱怨5
的默认类型都不能满足这些条件。
你很可能自己编写
instance (Integral a, RealFrac b, Floating b) => Integral (Either a b) where ...
instance (Integral a, RealFrac b, Floating b) => RealFrac (Either a b) where ...
instance (Integral a, RealFrac b, Floating b) => Floating (Either a b) where ...
(您还必须添加Num
,Ord
,Real
,Fractional
等实例),然后prime 5
将是可以接受,因为存在满足类型条件的5 :: Either Integer Float
。
答案 2 :(得分:3)
或者,您可以更改上限测试:
prime n = prime' n 2
where prime' n c | n `mod` c == 0 = False
| c * c > n = True
| otherwise = prime' n (c+1)
顺便说一句,你不需要n
作为prime'
的参数,因为它在所有调用中都是不变的。
答案 3 :(得分:2)
您可以将(sqrt n)
更改为(sqrt (fromInteger n))
,以使该功能按预期工作。这是必需的,因为sqrt
的类型是:
sqrt :: (Floating a) => a -> a
所以这是错误的,例如:
sqrt (2 :: Int)