簡體   English   中英

Haskell中的有狀態整數生成

[英]Stateful integer generation in Haskell

我想編寫一個Haskell函數來生成整數。 該函數將在第一次調用時返回1,然后在每次調用該函數時返回下一個整數。

在Python中,我使用了生成器的概念-整數生成器可能看起來像這樣:

def intGen():
    x = 1
    while True:
        yield x
        x += 1

integer = intGen()

# Use the generator
next(integer)    # 1
next(integer)    # 2
next(integer)    # 3

如何在Haskell中完成類似的操作? 我知道我可能需要State monad,但是我不確定如何設置它。 我對monad相當陌生。

Haskell是純函數,函數不能在相同的參數上生成不同的數據。

如果確實要使用它,則應使用IO aST a數據,例如IORef aSTRef a

但是您可以通過不同的方式使用純方法:

intGen = [1 .. 10]

intRes = map next intGen

使用IORef ,您可以執行類似的操作

import Data.IORef
import Control.Monad ((=<<))

type IntGen = IORef Int

intGen :: IO IntGen
intGen = newIORef 1

next :: IntGen -> IO Int
next gen = do
    val <- readIORef gen
    writeIORef gen $ val + 1
    return val

main :: IO ()
main = do
    integer <- intGen
    -- f =<< m == m >>= f
    print =<< next integer
    print =<< next integer
    print =<< next integer

或者,您可以僅使用State monad來做到這一點:

import Control.Monad.State

next :: Monad m => StateT Int m Int
next = do
    val <- get
    put $ val + 1
    return val

app :: StateT Int IO ()
app = do
    let stprint = liftIO . print
    stprint =<< next
    stprint =<< next
    stprint =<< next

main :: IO ()
main = void $ runStateT app 1

在第二個中,您的初始值是提供給runStateT1 ,因此它可以更靈活地從不同的值開始。


綜上所述,通常當您需要延遲生成的整數值時,可以使用列表。 例如,我可能有類似的東西

def processFile(directory):
    integer = intGen()
    for fname in os.listdir(directory):
        full_fname = os.path.join(directory, fname)
        if os.path.isfile(full_fname):
            i = next(integer)
            new_fname = '{}-{}'.format(i, fname)
            os.rename(full_fname, os.path.join(directory, new_fname))

但在Haskell中,我更喜歡寫類似

import Control.Monad
import System.Directory
import System.FilePath

processFiles :: FilePath -> IO ()
processFiles directory = do
    contents <- getDirectoryContents directory
    files <- filterM doesFileExist $ map (directory </>) contents
    forM_ (zip [1..] files) $ \(i, fname) -> do
        let newFName = show i ++ "-" ++ fname
        renameFile (directory </> fname) (directory </> newFName)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM