简体   繁体   English

Haskell在这里做了什么样的优化?

[英]What kind of optimizations does Haskell do here?

So, I'm admittedly a Haskell Newbie, but I so far like it a lot since I've been on a prime number splurge lately. 因此,我当然是Haskell Newbie的成员,但是到目前为止,我非常喜欢它,因为我最近一直在进行素数激增。 (Which is what turned me on to it) (这是让我着迷的原因)

I've got this relatively basic script. 我有这个相对基本的脚本。 It works exactly as it should, even if it's not as efficient as possible. 即使它效率不高,它也可以正常工作。 That's not my question though. 那不是我的问题。 Here is my script: 这是我的脚本:

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))

Like I said, simple. 就像我说的那样,很简单。 oddFactors goes through odd numbers from 3 to sqrt(p) and adds it to a list if it was a factor of p. 奇数oddFactors3sqrt(p)奇数,如果它是p的因数,则将其添加到列表中。

primes calls oddFactor s on 2^x -1 and checks if the resulting list is equal to the empty list. primes调用2^x -1上的oddFactor ,并检查结果列表是否等于空列表。

The weird thing is, it appears to already be optimized. 奇怪的是,它似乎已经被优化了。 In the case of primes if I were to do, for example, 61, my program takes 49 seconds to run and returns True. 对于primes ,例如61,我的程序需要49秒才能运行并返回True。 If I do 60 or 62, though, it takes .005s to run and returns False. 但是,如果我执行60或62,则需要运行0.005秒并返回False。 These are the correct return values, but I'm curious if it's optimized somehow since it knows it's only looking for a list matching [] and after finding one, it returns false, since the list will never be [] 这些是正确的返回值,但是我很好奇它是否经过某种方式的优化,因为它知道它只是在寻找一个匹配[]的列表,并且在找到一个列表之后,它会返回false,因为列表永远不会是[]

Long winded question, but I'm also willing to take any suggestions on my code so far. 冗长的问题,但到目前为止,我也愿意对我的代码提出任何建议。 I picked Haskell up about two hours ago, so be nice :) 我大约两个小时前就接过Haskell,所以要好:)

EDIT : I of course know I can use something better as a primality test, such as Miller-Rabin, but that's not the point ;) 编辑 :我当然知道我可以使用更好的东西作为初等性测试,例如Miller-Rabin,但这不是重点;)

The test list == [] will evaluate list only as much as needed to check the emptiness of list . 测试list == []将评估list作为需要检查的空虚只有尽可能多的list Technically, as much as needed to discover the outermost constructor of list (which could be : or [] ), bringing list to weak head normal form (WHNF). 从技术上讲,尽可能多地发现list的最外层构造函数(可以是:[] ),使list成为弱头范式(WHNF)。

For instance, (error "hello" : error "world") == [] will return False without evaluating the error expressions. 例如, (error "hello" : error "world") == []将返回False而不评估error表达式。

This results from expressions being lazily evaluated and the definition of (==) using pattern matching in the natural way: 这是由于表达式被懒惰地求值以及(==)的定义以自然方式使用模式匹配导致的:

[]     == []     = True
[]     == _      = False
_      == []     = False
(x:xs) == (y:ys) = x==y && xs==ys

By comparison, if the definition had been 相比之下,如果定义是

[]     == []     = True
[]     == (y:ys) = []==ys && False
(x:xs) == []     = xs==[] && False
(x:xs) == (y:ys) = x==y && xs==ys

then list == [] would have forced the computation of the whole list before returning False (or, more precisely, the whole list spine ). 那么list == []将在返回False (或更确切地说,整个列表spine )之前强制执行整个列表的计算。

Haskell lazily evaluates function calls. Haskell懒惰地评估函数调用。 That means it first tries to figure out the == "call" when evaluating, say prime 60 it tries to find the odd factors of 1152921504606846975 . 这意味着它首先在求值时尝试找出== “ call”,例如说prime 60它试图找到1152921504606846975的奇数因子。 When evaluating this, it will descend into the == definition, which for an empty list only tries to figure out if there is at least one element. 在评估时,它会归入==定义,对于一个空列表,它仅试图找出是否存在至少一个元素。 So effectively it only evaluates if 所以有效地它只会评估

1152921504606846975 `mod` 3 == 0

Since this is true, it doesn't even evaluate the rest of the list: It already knows 3:(stuff) == [] to be False , regardless of what (stuff) might evaluate to. 由于这是真的,所以它甚至不评估列表的其余部分:它已经知道3:(stuff) == []False ,而不管(stuff)可能会得出什么结果。

When you pass it 61 , it tries to find the odd factors of 2305843009213693951 , which is a prime, so it has to expand the hole list comprehension, in order to figure out that it is empty. 当您将其传递给61 ,它会尝试找到一个为质数的2305843009213693951的奇数因子,因此它必须扩展对孔列表的理解,才能确定其为空。 That's why it takes so long. 这就是为什么要花这么长时间的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM