所以,我确实是一个Haskell新手,但我到目前为止很喜欢它,因为我最近一直在使用素数挥霍。 (这是让我接受它的原因)
我有这个相对基本的脚本。即使它没有尽可能高效,它也能正常工作。但这不是我的问题。这是我的剧本:
import System.Environment
oddFactors p = [x | x<- [3,5..floor (sqrt (fromIntegral p))], p `mod` x == 0]
prime x = oddFactors (2^x -1) == []
main = do
args <- getArgs
print (prime (read (head args) :: Int))
像我说的那样简单。 oddFactors
会从3
到sqrt(p)
查看奇数,如果它是p的因子,则会将其添加到列表中。
primes
在oddFactor
上调用2^x -1
并检查结果列表是否等于空列表。
奇怪的是,它似乎已经被优化了。如果我要做primes
,例如61,我的程序需要49秒才能运行并返回True。但是,如果我执行60或62,则需要运行.005s并返回False。这些是正确的返回值,但我很好奇,如果它以某种方式进行优化,因为它知道它只查找匹配[]的列表,并且在找到它之后,它返回false,因为列表永远不会是[]
冗长的问题,但我也愿意对我的代码提出任何建议。大约两个小时前我选择了Haskell,所以要好看:)
编辑:我当然知道我可以使用更好的东西作为素性测试,例如Miller-Rabin,但这不是重点;)
答案 0 :(得分:5)
测试list == []
将仅根据检查list
空虚所需的内容评估list
。从技术上讲,尽可能多地发现list
的最外层构造函数(可能是:
或[]
),将list
置于弱头正常形式(WHNF)。< / p>
例如,(error "hello" : error "world") == []
将在不评估False
表达式的情况下返回error
。
这是由于表达式被懒惰地评估,而(==)
的定义是以自然的方式使用模式匹配:
[] == [] = True
[] == _ = False
_ == [] = False
(x:xs) == (y:ys) = x==y && xs==ys
相比之下,如果定义是
[] == [] = True
[] == (y:ys) = []==ys && False
(x:xs) == [] = xs==[] && False
(x:xs) == (y:ys) = x==y && xs==ys
然后list == []
会强制计算整个列表,然后再返回False
(或者更确切地说,整个list spine)。
答案 1 :(得分:3)
Haskell懒惰地评估函数调用。这意味着它首先试图找出==
&#34;电话&#34;评估时,说prime 60
它试图找到1152921504606846975
的奇数因子。在对此进行评估时,它将下降到==
定义,对于空列表,该定义仅尝试确定是否存在至少一个元素。所以有效它只评估是否
1152921504606846975 `mod` 3 == 0
由于这是真的,它甚至不会评估列表的其余部分:它已经知道3:(stuff) == []
为False
,无论(stuff)
可能评估什么。
当你传递它61
时,它试图找到2305843009213693951
的奇数因子,这是一个素数,所以它必须扩展孔列表理解,以便弄清楚它是空。这就是为什么需要这么长时间。