3

各要素間で「譲歩」し、その要素を出力に出力することを繰り返したい単純なリストがあります。これを行うために ContT モナドを使用しようとしていますが、問題が発生しています。これが私がこれまでに持っているものです:

data K a = Nil | K (a,() -> K a)
listIterator :: (Monad m) => [r] -> m (K r)
listIterator [] = return Nil
listIterator (x:xs) = return (ContT (\k -> K (x,k))) >> listIterator xs

runIterator :: IO ()
runIterator = do
  a <- listIterator ([1,2,3] :: [Int])
  let loop Nil = liftIO $ print "nil"
      loop (K (curr,newI)) =
          do
        liftIO $ print curr
        loop (newI ())
  loop a

予想される出力は次のとおりです。

1
2
3
nil

私が得るものは次のとおりです。

nil

どんな助けでも大歓迎です!

4

2 に答える 2

4
listIterator (x:xs) = return (ContT (\k -> K (x,k))) >> listIterator xs

あなたが期待することをしない、等式の推論

listIterator (x:xs) 
= return (ContT (\k -> K (x,k))) >> listIterator xs
= (return (ContT (\k -> K (x,k)))) >>= \_ -> listIterator xs
= (\_ -> listIterator xs) (ContT (\k -> K (x,k)))
= listIterator xs

イテレータを使用する理由が正確にはわかりません。Haskell はすでに遅延しているため、このような反復パターンは、需要主導の使用パターンとうまくやり取りする必要があるリソース管理の問題がある場合にのみ使用されることがほとんどです。そして、継続モナドはまったく必要ありません。

Kタプルを取るコンストラクタを書く代わりに、より慣用的です

data K a = Nil | K a (() -> K a)

直観的に、 の型はlistIteratorそのモナド構造を使用しません: 値を構築するだけなので、

listIterator ::[r] -> K r
listIterator [] = Nil
listIterator (x:xs) = K x (\_ -> listIterator xs)

今、人生は些細なことです

runIterator :: IO ()
runIterator = do
 let a = listIterator ([1,2,3] :: [Int])
     loop Nil = liftIO $ print "nil"
     loop (K curr newI) =
         do
       liftIO $ print curr
       loop (newI ())
 loop a

do表記を使わずに書くのがおそらく最善でしょう。

于 2012-07-22T18:42:59.863 に答える
1

これはあなたが探していた答えではないかもしれませんが、このスタイルのプログラミングに興味がある場合はpipes、同様のライブラリを調べる必要があります。(conduitは「現実の世界」では新星ですが、pipes は教育用のより簡単なツールを提供するため、ここで使用します。)

$ cabal update && cabal install pipes

パイプは、入力を取得できるもの (コンシューマー)、出力を生成するもの (プロデューサー)、および両方を行うもの (パイプ) の 3 つのフレーバーがあることを除いて、イテレーターに似ています。入力端と出力端がすべて満たされるようにパイプを接続すると、それは「パイプライン」と呼ばれ、追加の入力なしで実行できる自己完結型のユニットです。

Pipe は、パイプの作成に便利なモナドのインスタンスを提供します。オペレーターは、2 つの>+>パイプを一緒に接続します。

import Control.Pipe
import Control.Monad.Trans.Class
import Control.Monad.IO.Class

-- annoyingly, Pipe does not provide a MonadIO instance
instance (MonadIO m) => MonadIO (Pipe a b m) where
  liftIO = lift . liftIO

listIterator :: Monad m => [a] -> Producer (Maybe a) m ()
listIterator (x:xs) = yield (Just x) >> listIterator xs
listIterator []     = yield Nothing

printer :: (MonadIO m, Show a) => Consumer (Maybe a) m ()
printer = do
  mx <- await
  case mx of
    Just x -> liftIO (print x) >> printer
    Nothing -> liftIO (putStrLn "nil")

main = runPipe $ listIterator [1, 2, 3] >+> printer

Control.Pipeのソースは、Gabriel の Free monads に関する最近のブログ投稿、特にWhy free monads matterPurify code using free monads を読んでいる場合は特に、非常にシンプルです。

于 2012-07-22T23:53:08.217 に答える