8

Threepenny-GUIという Haskell のグラフィック ライブラリを使用しています。このライブラリでは、メイン関数はUIモナド オブジェクトを返します。IOこれは、値をローカル変数にアンパックしようとすると、さまざまなモナド型について不平を言うエラーが発生するため、頭痛の種になります。

これが私の問題の例です。これは、Threepenny-GUI のコード例で示されているように、標準の main 関数のわずかに変更されたバージョンです。

main :: IO ()
main = startGUI defaultConfig setup

setup :: Window -> UI ()
setup w = do

labelsAndValues <- shuffle [1..10]

shuffle :: [Int] -> IO [Int]
shuffle [] = return []
shuffle xs = do randomPosition <- getStdRandom (randomR (0, length xs - 1))
                let (left, (a:right)) = splitAt randomPosition xs
                fmap (a:) (shuffle (left ++ right))

5 行目に注意してください。

labelsAndValues <- shuffle [1..10]

次のエラーが返されます。

Couldn't match type ‘IO’ with ‘UI’
Expected type: UI [Int]
  Actual type: IO [Int]
In a stmt of a 'do' block: labelsAndValues <- shuffle [1 .. 10]

私の質問に関してはIO、標準の矢印表記 ( <-) を使用して関数をアンパックし、これらの変数をIO ()ではなくとして保持し続けるとUI ()、他の関数に簡単に渡すことができます。

現在、私が見つけた唯一の解決策は を使用することでしたliftIOが、これによりUIモナド型への変換が発生しますが、実際には型を使い続けたいと思っていIOます。

4

3 に答える 3

8

ブロックは特定のdoタイプのモナド用であり、途中でタイプを変更することはできません。

アクションを変換するか、 内にネストすることができますdo。ほとんどの場合、変換の準備が整います。たとえば、ネストされたものを使用して、相互作用の時点でのみ変換することができdoますio

あなたの場合、liftIOLaterThreePennyUI パッケージによってこれを処理する関数が提供されます。

liftIOLater :: IO () -> UI ()

IO アクションを後で実行するようにスケジュールします。

逆変換を実行するには、次を使用できますrunUI

runUI :: Window -> UI a -> IO a

特定のブラウザ ウィンドウで UI アクションを実行します。スケジュールされたすべての IO アクションも実行します。

于 2015-06-22T13:29:38.253 に答える