Arrays 如何通过1)使用数组,2)避免列表串联(惰性列表?)来改进该算法?
我试着去学习星空是如何工作的,但我做不到。(医生很差,或者至少是我找到的那个) 无论如何,我有下一个算法,但它使用了很多!!,这很慢。如何将其转换为使用STArray monadArrays 如何通过1)使用数组,2)避免列表串联(惰性列表?)来改进该算法?,arrays,haskell,monads,st-monad,starray,Arrays,Haskell,Monads,St Monad,Starray,我试着去学习星空是如何工作的,但我做不到。(医生很差,或者至少是我找到的那个) 无论如何,我有下一个算法,但它使用了很多!!,这很慢。如何将其转换为使用STArray monad -- The Algorithm prints the primes present in [1 .. n] main :: IO () main = print $ primesUpTo 100 type Nat = Int primesUpTo :: Nat -> [Nat] primesUpTo n
-- The Algorithm prints the primes present in [1 .. n]
main :: IO ()
main = print $ primesUpTo 100
type Nat = Int
primesUpTo :: Nat -> [Nat]
primesUpTo n = primesUpToAux n 2 [1]
primesUpToAux :: Nat -> Nat -> [Nat] -> [Nat]
primesUpToAux n current primes =
if current > n
then primes
else primesUpToAux n (current + 1) newAcum
where newAcum = case isPrime current primes of
True -> primes++[current]
False -> primes
isPrime :: Nat -> [Nat] -> Bool
isPrime 1 _ = True
isPrime 2 _ = True
isPrime x neededPrimes = isPrimeAux x neededPrimes 1
isPrimeAux x neededPrimes currentPrimeIndex =
if sqrtOfX < currentPrime
then True
else if mod x currentPrime == 0
then False
else isPrimeAux x neededPrimes (currentPrimeIndex + 1)
where
sqrtOfX = sqrtNat x
currentPrime = neededPrimes !! currentPrimeIndex
sqrtNat :: Nat -> Nat
sqrtNat = floor . sqrt . fromIntegral
--算法打印[1..n]中的素数
main::IO()
main=打印$primesup到100
类型Nat=Int
primesUpTo::Nat->[Nat]
primesUpTo n=primesUpToAux n 2[1]
primesUpToAux::Nat->Nat->[Nat]->[Nat]
primesUpToAux n当前primes=
如果当前>n
然后素数
else primesUpToAux n(当前+1)newAcum
其中newAcum=情况isPrime当前素数
True->primes++[当前]
假->素数
iPrime::Nat->[Nat]->Bool
iPrime 1=真
iPrime 2=真
isPrime x neededPrimes=isPrimeAux x neededPrimes 1
isPrimeAux x所需素数currentPrimeIndex=
如果sqrtOfXNat
sqrtNat=地板。sqrt。从积分
编辑
哎哟,这个!!这不是问题所在;在下一个版本的算法(如下)中,我删除了!!;此外,我还将1固定为素数,正如@pedrorodrigues所指出的,它不是素数
main :: IO ()
main = print $ primesUpTo 20000
type Nat = Int
primesUpTo :: Nat -> [Nat]
primesUpTo n = primesUpToAux n 1 []
primesUpToAux :: Nat -> Nat -> [Nat] -> [Nat]
primesUpToAux n current primesAcum =
if current > n
then primesAcum
else primesUpToAux n (current + 1) newPrimesAcum
where newPrimesAcum = case isPrime current primesAcum of
True -> primesAcum++[current]
False -> primesAcum
isPrime :: Nat -> [Nat] -> Bool
isPrime 1 _ = False
isPrime 2 _ = True
isPrime x neededPrimes =
if sqrtOfX < currentPrime
then True
else if mod x currentPrime == 0
then False
else isPrime x restOfPrimes
where
sqrtOfX = sqrtNat x
currentPrime:restOfPrimes = neededPrimes
sqrtNat :: Nat -> Nat
sqrtNat = floor . sqrt . fromIntegral
main::IO()
main=print$primesUpTo 20000
类型Nat=Int
primesUpTo::Nat->[Nat]
primesUpTo n=primesUpToAux n 1[]
primesUpToAux::Nat->Nat->[Nat]->[Nat]
primesUpToAux n当前primesAcum=
如果当前>n
然后是primesAcum
else primesUpToAux n(当前+1)NEWSPRIMESACUM
其中newPrimesAcum=案例i当前primesAcum
True->primesAcum++[当前]
假->素数
iPrime::Nat->[Nat]->Bool
iPrime 1=错误
iPrime 2=真
isPrime x所需素数=
如果sqrtOfXNat
sqrtNat=地板。sqrt。从积分
现在这个问题实际上是关于两个问题:
1.-如何将此算法转换为使用数组而不是列表?(是为了学习如何在Haskell中处理状态和数组)
有人在评论中已经回答了这个问题,但指出了一个不太好的例子
2.-如何在每次发现新素数时消除列表的串联?
True->primesAcum++[当前]
下面是您的代码到使用非固定整数数组的大致直接转换:
import Control.Monad
import Control.Monad.ST
import Data.Array.ST
import Data.Array.Unboxed
import Control.Arrow
main :: IO ()
main = print . (length &&& last) . primesUpTo $ 1299709
primesUpTo :: Int -> [Int]
primesUpTo = takeWhile (> 0) . elems . primesUpToUA
primesUpToUA :: Int -> UArray Int Int
primesUpToUA n = runSTUArray $ do
let k = floor( 1.25506 * fromIntegral n / log (fromIntegral n)) -- WP formula
ar <- newArray (0,k+1) 0 -- all zeroes initially, two extra spaces
let
loop c i | c > n = return ar -- upper limit is reached
| otherwise = do -- `i` primes currently in the array
b <- isPrime 0 i c -- is `c` a prime?
if b then do { writeArray ar i c ; loop (c+1) (i+1) }
else loop (c+1) i
isPrime j i c | j >= i = return True -- `i` primes
| otherwise = do -- currently in the array
p <- readArray ar j
if p*p > c then return True
else if rem c p == 0 then return False
else isPrime (j+1) i c
loop 2 0
import-Control.Monad
进口管制站
导入Data.Array.ST
导入Data.Array.unbox
导入控制。箭头
main::IO()
main=打印。(长度和最后一个)。价格降至1299709美元
primesUpTo::Int->[Int]
primesUpTo=takeWhile(>0)。元素。普莱姆苏普图亚酒店
primesUpToUA::Int->UArray Int
primesUpToUA n=runSTUArray$do
设k=地板(1.25506*从积分n/对数(从积分n))--WP公式
ar n=返回ar——达到上限
|否则=do--`i`当前在数组中的素数
b=i=返回真--`i`素数
|否则=do--当前在数组中
然后返回True
否则,如果rem c p==0,则返回False
else isPrime(j+1)i c
环路20
这或多或少是不言自明的,当你慢慢读的时候,一次读一句话
使用数组时,列表连接没有问题,因为没有列表。我们在添加新项时使用素数数组
当然,您可以重新编写基于列表的代码,使其表现得更好;是
ps::[Int]
ps=2:[i | i 0 | p此处不需要STArray,该算法只是尝试除法。您应该看看标准的列表操作函数(filter
,takeWhile
,all
,any
,等等)首先,我认为,因为使用它们可以以最佳方式和惯用方式解决问题,而在这里,您走了相当多的弯路。您希望以函数式的方式快速实现吗?请参阅前面的评论(并确保避免盲目地用列表表示集合的谬误)或者:你想学习使用STArray,然后准确地描述你对STArray的问题所在。你意识到你必须编写“命令式”代码(所有内容都在ST monad中)顺便说一句,1不是素数。Haskell wiki有一个使用ST数组计算素数的例子:来解决你的第二个问题:与其做primesAcum++[current]
,也就是O(n^2),不如做current:primesAcum
,并反转最后的列表,也就是O(n)非常感谢。有一个问题,我知道newArray(0,k+1)0生成一个sts(STUArray s Int Int),对吗?s(state)的类型是什么?我也不知道isPrime的类型。要查看任何实体的类型,例如isPrime
,请添加let x=isPrime==True
,并读取有关Bool
-和您想要知道的类型之间类型不匹配的错误消息。--我们知道runSTUArray::Ix I=>(对于所有s.ST s(stu数组I-e))->UArray i e
,因此其中的do
表达式是::Ix i=>(对于所有s.ST s(STU数组i e))
。(…cont)(…contd)因此,do表达式中的计算是在ST s
单子中。s
被所有s的封装,所以我们不知道它是什么,也一定不知道。所以m~ST s
与不可见的s
一起
ps :: [Int]
ps = 2 : [i | i <- [3..],
and [rem i p > 0 | p <- takeWhile ((<=i).(^2)) ps]]
primesTo n = takeWhile (<= n) ps