5

ラズベリーパイの別のピンから取得した割り込みに応じて、ラズベリーパイのピンを切り替えるためのhaskellコードをいくつか作成しました。以前のトグル状態を知らずにピンの状態をトグルする方法がわかりません。プログラム自体はとてもシンプルです。

 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

つまり、基本的にここで発生するのは、ピン7が割り込みとして登録されていることです。ピン7がハイからローまたはローからハイになるたびに割り込みがトリガーされます。また、割り込みがトリガーされるたびに、onoffピン0の状態を切り替える関数が呼び出されます。

main機能は正しいです。そのonoff機能が問題です。この関数の目的の動作は、onoffピンがローのときにピン0をハイにし、ハイのときにピンをローに切り替えることです。ただし、これを行うには、の前の呼び出しでピンの前の状態を保存する必要がありますonoff

州のモナドを試してみました。しかし、問題は、状態モナドが初期状態値に基づいて状態を渡すことです。しかし、その後の呼び出しonoffでは、初期状態値を変更することは不可能のようです。IORefについて考えましたが、違いはないようです。状態が実行していることを実行しているように見えますが、IO内でのみ実行されます。

状態をグローバル変数に格納する機能が非常に不足していることがはっきりとわかります。そして、同じ目標を達成するための他の慣用的な方法があることを知っているので、私はそれを行うことができないことを嬉しく思います。

正しい方向への助けは大歓迎です。

乾杯とよろしく。

4

2 に答える 2

7

Stateモナドは、実際には、状態を追加のパラメーターで関数に渡すという考えを抽象化したものです。これはまだ純粋であり、多くの構文上のヘルプを提供します。IORef一方、実際の変更可能な値の実際の更新であるため、IOモナド内に存在する必要があります。これは、パフォーマンス上の理由から必要でない限り、一般的に望ましくないと考えられています。遅延性、実行順序、および同時実行性に関する純粋なコードで得られるすべての約束が失われるからです。

Stateand を一緒に使用IOするには、StateT モナド変換子を使用します。これは、State モナドを IO モナドにラップするものと考えることができます。Haskell wiki にいくつかの例があります: http://www.haskell.org/haskellwiki/Simple_StateT_useでは、I/O を使用しながら状態を維持する方法と、lift内部で IO モナド関数を実行するために使用する方法を示していますStateT

于 2013-03-12T09:07:08.880 に答える
1

ここに小さな例があります。それが慣用的なHaskellかどうかはわかりませんが、正しい軌道に乗るには十分なはずです. 実際にピンを切り替えるのではなく (テストする Raspberry Pi はありません)、状態を出力するだけです。どちらも IO () ですが、一致するはずです。

あなたの実際の状態は、おそらくピンのレコード/リスト/配列になるでしょう。次に、インデックスを togglePin に渡すと、次のようなタイプになります。

togglePin :: Int -> PStateT

とにかく、これが例です。ここではコンパイルして正常に実行されます。

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 ()
于 2013-03-12T17:58:49.467 に答える