How to simulate haskell state?

I wrote haskell code to switch a pin on a raspberry pi depending on the interrupt that I get from another pin on a raspberry pi. I just don't know how to switch the pin state without knowing the previous switch state. The program itself is very simple.

import Control.Concurrent import Data.IORef import HasberryPi main = do wiringPiSetup pinMode 0 output pinMode 7 input pullUpDnControl 7 pull_down wiringPiISR 7 edge_both onoff threadDelay (15*(10^6)) onoff s = do a <- readIORef s -- This is wrong digitalWrite 0 (if b then pinhigh else pinlow) -- This is wrong 

So basically what happens here, pin 7 is registered as an interrupt. An interrupt is triggered when pin 7 goes from high to low or from low to high. And whenever an interrupt is triggered, it calls the onoff function, which switches the state of pin 0.

The main function is correct. Its onoff function is a problem. The desired behavior of the onoff function is to make pin 0 high when the pin is low, and to switch low contact when it is high. But for this I need to save the previous pin state in the previous onoff call.

I tried the state monad. But the problem is that the state monad passes the state around based on the initial value of the state. But in subsequent onoff calls, onoff seems impossible to change the initial state value. I was thinking about IORef and that is no different. It seems that he is doing what the state is doing, but only inside the IO.

I clearly see that I really lack the ability to save state in a global variable. And I am glad that I am not able to do this, because I know that there is some other idiomatic way to achieve the same goal.

Any help in the right direction is greatly appreciated.

Greetings and greetings.

+4
source share
2 answers

The State monad is really an abstraction over the idea of ​​passing state in an additional parameter to your functions - it is still clean, it just gives you syntactic help. IORef , on the other hand, is an actual update of the actual mutable value, so it must live inside the IO monad. This is usually considered undesirable if it is not required for performance reasons, since you lose all the promises that you get with clean code about laziness and execution order, and concurrency.

The use of State and IO together is achieved using the StateT monad transformer, which can be thought of as wrapping the state monad around the IO monad. There are several examples on the Haskell wiki directory: http://www.haskell.org/haskellwiki/Simple_StateT_use , which shows how you maintain state when using I / O and how to use lift to get IO monodata functions inside StateT .

+6
source

Here is a small example. I'm not sure if this is an idiomatic Haskell, but that should be enough to get you on the right track. Instead of actually switching the pin (I don't have a raspberry test), it just prints the state. They are both IO (), although they must match.

Your real state, apparently, will consist of entries / list / contacts array. Then you pass the togglePin index and it will have a type type

 togglePin :: Int -> PStateT 

Anyway - here is an example, it compiles and works 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 level too rather than -- just print it 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 () 
0
source

All Articles