我昨天已经开始学习Haskell,所以你可以认为我是一个完全的新手。
我想要一个质数列表,所以我说:
multiples max reihe = [ x | x <- [reihe*2,reihe * 3..max], x<= max ]
notPrimes max = [ truncate x | x <- concat [ multiples max reihe | reihe <- [2..(max/2)]]]
primes max = [ x | x <- [2..max] , elem x (notPrimes max) ]
第一个代码片段是一个函数,它返回不超过max
的所有reihe
倍数。
第二个是返回除1之外的所有非素数的函数,直到指定的最大值。
最后一个片段不起作用,我不明白为什么。如果我用任意值x
评估elem x (notPrimes max)
,我会得到答案,但这个"过滤器"会抛出一个错误:
<interactive>:47:1: error:
* Ambiguous type variable `a0' arising from a use of `print'
prevents the constraint `(Show a0)' from being solved.
Probable fix: use a type annotation to specify what `a0' should be.
These potential instances exist:
instance Show Ordering -- Defined in `GHC.Show'
instance Show a => Show (Maybe a) -- Defined in `GHC.Show'
instance Show Integer -- Defined in `GHC.Show'
...plus 23 others
...plus 15 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
* In a stmt of an interactive GHCi command: print it
问题在于使用由/
运算符引起的小数。
当函数truncate
从某种RealFrac
类型转换为某种Integral
类型时,以下等式:
notPrimes max = [ truncate x | x <- concat [ multiples max reihe | reihe <- [2..(max/2)]]
将强制参数max
为分数,并将notPrimes
的结果作为整数值的列表。
但是,这个等式:
primes max = [ x | x <- [2..max] , elem x (notPrimes max) ]
将迫使x
像max
一样是分数,像notPrime max
元素一样是积分。请记住,Haskell不进行隐式类型转换。
因此,当你试图实际评估类似primes 100
的东西时,你强迫Haskell解释器为每个事物分配实际类型,事情变得丑陋。
关键思想是:
- 不要在整数问题中使用小数,除非确实有必要
- 酌情使用显式类型签名
此外,正如评论中提到的,缺少一个逻辑否定(一个额外的not
调用)。
可能的仅积分解决方案:
$ ghci
GHCi, version 8.8.4: https://www.haskell.org/ghc/ :? for help
λ>
λ> :type (/)
(/) :: Fractional a => a -> a -> a
λ>
λ> :type div
div :: Integral a => a -> a -> a
λ>
λ> multiples max reihe = [ x | x <- [reihe*2,reihe * 3..max], x<= max ]
λ> notPrimes max = [ x | x <- concat [ multiples max reihe | reihe <- [2..(div max 2)]]]
λ> primes max = [ x | x <- [2..max] , not $ elem x (notPrimes max) ]
λ>
λ> primes (100::Int)
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97]
λ>