hsk*_*new 8 primes haskell short-circuiting
我是Haskell的新手,我正在尝试一下:
isPrime :: Integer->Bool
isPrime x = ([] == [y | y<-[2..floor (sqrt x)], mod x y == 0])
Run Code Online (Sandbox Code Playgroud)
我有几个问题.
(Floating Integer, RealFrac Integer)定义所需的实例isPrime?抱歉我的英语.
Lan*_*dei 17
1)问题是sqrt具有类型(Floating a) => a -> a,但您尝试使用Integer作为参数.因此,您必须先将Integer转换为浮动,例如通过写入sqrt (fromIntegral x)
2)我没有理由为什么==不应该是懒惰的,但是为了测试一个空集合你可以使用该null函数(这绝对是懒惰的,因为它适用于无限列表):
isPrime :: Integer->Bool
isPrime x = null [y | y<-[2..floor (sqrt (fromIntegral x))], x `mod` y == 0]
Run Code Online (Sandbox Code Playgroud)
但是为了获得更加惯用的解决方案,将问题分解为更小的子问题.首先,我们需要y*y <= x的所有元素y的列表:
takeWhile (\y -> y*y <= x) [2..]
Run Code Online (Sandbox Code Playgroud)
那么我们只需要划分x的元素:
filter (\y -> x `mod`y == 0) (takeWhile (\y -> y*y <= x) [2..])
Run Code Online (Sandbox Code Playgroud)
然后我们需要检查该列表是否为空:
isPrime x = null (filter (\y -> x `mod`y == 0) (takeWhile (\y -> y*y <= x) [2..]))
Run Code Online (Sandbox Code Playgroud)
如果这看起来像你的lispy,用$替换一些parens
isPrime x = null $ filter (\y -> x `mod` y == 0) $ takeWhile (\y -> y*y <= x) [2..]
Run Code Online (Sandbox Code Playgroud)
为了更加清晰,您可以"外包"lambda:
isPrime x = null $ filter divisible $ takeWhile notTooBig [2..] where
divisible y = x `mod`y == 0
notTooBig y = y*y <= x
Run Code Online (Sandbox Code Playgroud)
你可以通过用$ any替换null $ filter来使它几乎"人类可读":
isPrime x = not $ any divisible $ takeWhile notTooBig [2..] where
divisible y = x `mod`y == 0
notTooBig y = y*y <= x
Run Code Online (Sandbox Code Playgroud)
因为sqrt有类型Floating a => a -> a.这意味着输入必须是一个Floating类型,输出将是相同的类型.换句话说,x需要是一种Floating类型.但是,您声明x为类型Integer,而不是Floating类型.另外floor需要一种RealFrac类型,所以也x需要这样.
该错误消息表明,您修复,通过使Integer一个Floating类型(通过定义一个实例Floating Integer(与同为RealFrac).
当然,在这种情况下,这不是正确的方法.相反,你应该使用fromIntegral转换x到Real(这是实例Floating和RealFrac),然后把那个给sqrt.
是.一旦==看到右操作数至少有一个元素,它就知道它不等于[]并因此返回False.
话虽这么说,null检查列表是否为空是一种更惯用的方式[] ==.