首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用可变状态计算的惰性列表?

使用可变状态计算的惰性列表?
EN

Stack Overflow用户
提问于 2012-07-22 05:58:01
回答 1查看 320关注 0票数 5

我想了解一下如何在计算惰性列表时使用可变状态。

例如,下面是一个使用可变数组(source)实现的Eratosthenes的简单筛子:

代码语言:javascript
复制
import Control.Monad.ST
import Data.Array.ST
import Data.Array.Unboxed
import Control.Monad
import Data.List

prime :: Int -> UArray Int Bool
prime n = runSTUArray $ do
    arr <- newArray ( 2 , n ) True :: ST s ( STUArray s Int Bool )
    forM_ ( takeWhile ( \x -> x*x <= n ) [ 2 .. n ] ) $ \i -> do
        ai <- readArray arr i
        when ( ai  ) $ forM_ [ i^2 , i^2 + i .. n ] $ \j -> do
            writeArray arr j False
            -- yield i ???

prime n返回一个布尔值数组,表示哪些数字是质数。

有没有办法使用这种方法来创建这些素数的惰性列表?这就像在writeArray语句后面添加一个yield i

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-07-22 06:19:07

为了实现惰性,对程序进行的最小修改可能是切换到lazy ST monad (http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Monad-ST-Lazy.html),下面的代码可以在这里工作:

代码语言:javascript
复制
import Control.Monad.ST.Lazy
import Data.Array.ST
import Data.Array.Unboxed
import Control.Monad
import Data.List
import Data.Maybe

prime :: Int -> [Int]
prime n = catMaybes $ runST $ do
    arr <- strictToLazyST $ newArray ( 2 , n ) True :: ST s ( STUArray s Int Bool )
    forM ( takeWhile ( \x -> x <= n ) [ 2 .. n ] ) $ \i -> do
        if i == 83 then error "Reached 83" else return ()
        ai <- strictToLazyST $ readArray arr i
        if ai
          then do
            strictToLazyST $ forM_ [ i^2 , i^2 + i .. n ] $
                 \j -> writeArray arr j False
            return (Just i)
          else return Nothing

错误调用只是为了演示结果的真正惰性:

代码语言:javascript
复制
*Main> prime 10000
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79*** Exception: Reached 83

例如,如果您希望避免使用Maybes的中间列表,则可以使用以下代码:

代码语言:javascript
复制
import Control.Monad.ST.Lazy
import Data.Array.ST
import Data.Array.Unboxed
import Control.Monad
import Data.List
import Data.Functor

prime :: Int -> [Int]
prime n = runST $ do
    arr <- strictToLazyST $ newArray ( 2 , n ) True :: ST s ( STUArray s Int Bool )
    let primesFrom i | i > n = return []
                     | otherwise = do
            ai <- strictToLazyST $ readArray arr i
            if ai then do
                strictToLazyST $ forM_ [ i^2 , i^2 + i .. n ] $
                   \j -> writeArray arr j False
                (i:) <$> primesFrom (i + 1)
              else primesFrom (i + 1)
    primesFrom 2
票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11596151

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档