1) 问题在于 sqrt
的类型是 (Floating a) => a -> a
,但您尝试使用整数作为参数。因此,您必须先将整数转换为浮点数,例如编写 sqrt (fromIntegral x)
2) 我看不出为什么 == 不应该是惰性的,但是要测试空集合,可以使用 null
函数(它绝对是惰性的,因为它适用于无限列表):
isPrime :: Integer->Bool
isPrime x = null [y | y<-[2..floor (sqrt (fromIntegral x))], x `mod` y == 0]
为了获得更具通俗易懂的解决方案,我们需要将问题分解成较小的子问题。首先,我们需要一个包含所有满足 y*y <= x 的元素y的列表:
takeWhile (\y -> y*y <= x) [2..]
我们只需要能够整除x的元素:
filter (\y -> x `mod`y == 0) (takeWhile (\y -> y*y <= x) [2..])
然后我们需要检查该列表是否为空:
isPrime x = null (filter (\y -> x `mod`y == 0) (takeWhile (\y -> y*y <= x) [2..]))
如果这看起来对你来说太像Lisp了,可以用 $ 符号替换一些括号
isPrime x = null $ filter (\y -> x `mod` y == 0) $ takeWhile (\y -> y*y <= x) [2..]
为了更加清晰,您可以“外包”这些Lambda函数:
isPrime x = null $ filter divisible $ takeWhile notTooBig [2..] where
divisible y = x `mod`y == 0
notTooBig y = y*y <= x
你可以将 null $ filter 替换为 not $ any,使其几乎“可读性好于人类”。
isPrime x = not $ any divisible $ takeWhile notTooBig [2..] where
divisible y = x `mod`y == 0
notTooBig y = y*y <= x