在特定情况下,我试图通过执行基本任务来学习一些Haskell,我试图实现一些用于素数检查的基本功能,但是我真的可以弄清楚类型,我的代码是
isPrime :: (Num a) => a -> Bool
isPrime n
| n <= 1 = False
| otherwise = not $ 0 `elem` map (mod n) [2..m] where m = floor $ sqrt n
我尝试代替(Num a) => a
使用不同的数字类型或将sqrt
与fromIntegral
一起使用,但仍然收到错误消息,例如:
*Could not deduce (Floating a) arising from a use of `sqrt'
from the context: Num a
bound by the type signature for:
isPrime :: forall a. Num a => a -> Bool
at Helpers.hs:5:1-31
Possible fix:
add (Floating a) to the context of
the type signature for:
isPrime :: forall a. Num a => a -> Bool
* In the second argument of `($)', namely `sqrt n'
In the expression: floor $ sqrt n
In an equation for `m': m = floor $ sqrt n
| otherwise = not $ 0 `elem` map (mod n) [2..m] where m = floor $ sqrt n
我真的可以在这里使用一些帮助,谢谢。
答案 0 :(得分:4)
正如其他人所提到的,使用mod
要求a
为Integral
,使用sqrt
要求a
为{{1 }}。从函数的名称来看,我假设您要在整数类型上使用它。
因此,您可以通过以下方法解决此问题:将签名更改为Floating
,然后用isPrime :: (Integral a) => a -> Bool
预先组成sqrt
。你可以做类似的事情
fromIntegral
另一种选择是将where m = floor . sqrt . fromIntegral $ n
替换为[1..m]
,以避免需要takeWhile (\x -> x * x <= n) [1..]
。
答案 1 :(得分:3)
您的代码中有两个问题:
同时调用sqrt n
和(mod n)
都要求n分别为Floating
和Integral
。
(Num a)
不允许进行任何两项操作。可能的解决方法是:a)将类型上下文范围缩小到更简洁的(Integral a)
; b)将fromIntegral
添加到sqrt
的参数中:
isPrime :: Integral a => a -> Bool
isPrime n
| n <= 1 = False
| otherwise = not $ 0 `elem` map (mod n) [2..m] where m = floor $ sqrt $fromIntegral n
答案 2 :(得分:1)
编译器描述的问题是您将不兼容的操作应用于同一类型:mod
要求Integral a
,sqrt
要求Floating a
,并且没有类型可以满足都。您可以使用fromIntegral
和ceiling
之类的类型转换来解决此问题,但是您要小心避免舍入错误。在测试中,我删除了类型约束并使用了m = ceiling $ sqrt $ fromIntegral n
,这导致了推断出的类型isPrimeSqrt :: Integral a => a -> Bool
。
另一种方法是考虑为什么会发生冲突并寻找其他解决方案。 sqrt
的原因是为测试产生优化的停止点。我们可以用另一种方式找到那个停止点吗?
mod
,您需要寻找后者,但是我们同时拥有divMod
和quotRem
。因此,如果这比普通的mod
测试(benchmark results(将[2..]
与[2..m]
进行比较)显着慢,则值得进行测试。
isPrime n = (n > 1) && null (filter isFactor (takeWhile notTooHigh divisors))
where notTooHigh (divisor,quotient,_) = divisor <= quotient
isFactor (_,_,remainder) = remainder == 0
divisors = [(divisor,quotient,remainder) |
divisor <- 2:[3,5..],
let (quotient,remainder) = quotRem n divisor]