how to simulate haskell state?

霸气de小男生 提交于 2019-12-03 16:54:43

The State monad is really an abstraction over the idea of passing state around in an extra parameter to your functions - it's still pure, it just gives you a lot of syntactic help. IORef, on the other hand, is an actual update of an actual mutable value, which is why it has to live inside the IO monad. This is generally considered undesirable unless required for performance reasons, as you lose all the promises you get with pure code about laziness and order of execution and concurrency.

Using State and IO together is achieved by use of the StateT monad transformer, which might be thought of as wrapping the State monad around the IO monad. There are some examples on the Haskell wiki: http://www.haskell.org/haskellwiki/Simple_StateT_use which shows how you maintain state while using I/O, and how to use lift to get IO monad functions to run inside StateT.

Here's a small example. I'm not sure if it's idiomatic Haskell but it should be enough to get you on the right track. Rather than actually toggling a pin (I don't have a Raspberry Pi to test against) it just prints the state. They're both IO () though so it should match.

Your real state would presumably be a record/list/array of pins. You'd then pass in an index to togglePin and it would have a type like

togglePin :: Int -> PStateT

Anyway - here's the example, it compiles and runs fine here.

import Control.Monad.State

-- Presumably you've got something like this defined in a library
data Pin = PinHigh | PinLow
    deriving (Eq,Show)

-- A simple state would be
-- type PState = State Pin
-- We want to wrap our state around IO () so need a transformer
type PStateT = StateT Pin IO ()

-- Simple print function
printPinState :: String -> Pin -> IO ()
printPinState msg pin = putStrLn $ msg ++ (show pin)

-- Toggles the state, real function would set the pin's level too rather than 
-- just print it's new state
togglePin :: PStateT
togglePin = do
    curr_p <- get
    lift $ printPinState "toggle before: " curr_p
    let new_p = if curr_p == PinHigh then PinLow else PinHigh
    lift $ printPinState "toggle after:  " new_p
    put new_p
    return ()

-- Initialise our state, then run our toggle function using the state
-- as its environment.
main = do
    let env = PinLow
    printPinState "main before:   " env
    (_, env') <- runStateT (togglePin) env
    printPinState "main after:    " env'
    -- And again for luck...
    (_, env'') <- runStateT (togglePin) env'
    return ()
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!