【发布时间】:2025-12-19 00:30:02
【问题描述】:
我试图了解 STArray 的工作原理,但我学不会。 (Doc很差,或者至少是我找到的那个)。
无论如何,我有下一个算法,但它使用了很多!!,这很慢。如何将其转换为使用 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 = 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 固定为素数,正如@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
现在这个问题实际上是关于 2 个问题:
1.- 如何将此算法转换为使用数组而不是列表?(是为了学习如何在 Haskell 中处理状态和数组) 有人已经在 cmets 中回答了,但指向一个不太好的解释示例。
2.- 每次发现新素数时如何消除列表的串联?
真 -> primesAcum++[当前]
【问题讨论】:
-
这里不需要STArray,算法只是试用分区。我认为,您应该先查看标准列表操作函数(
filter、takeWhile、all、any等),因为可以使用它们以最佳方式和惯用方式解决问题,在这里你'正在绕弯路。 -
您想要一个功能风格的快速实现?然后查看之前的评论(并确保避免盲目地用列表表示集合的谬误)。或者:您想学习使用 STArray - 然后准确描述您使用 STArray 的问题。你意识到你必须编写“命令式”代码(一切都在 ST monad 中)。
-
1 不是质数,顺便说一下。
-
Haskell wiki 有一个使用 ST 数组计算素数的示例:haskell.org/haskellwiki/Prime_numbers#Using_ST_Array
-
解决您的第二个问题:不要执行
primesAcum++[current],即 O(n^2),而是执行current:primesAccum并在最后反转列表,即 O(n)。
标签: arrays haskell monads st-monad starray