2013-12-21 13 views
9

リストの理解は非常に分かりやすいです。次の定義のhを見てください。それはリストのタイプ[Int]およびpure_fpure_xsを使用し、リストの両方の理解を使用します。ハスケルのモナディックリストの理解

pure_xs :: [Int] 
pure_xs = [1,2,3] 

pure_f :: Int -> String 
pure_f a = show a 

h :: [(Int,Char)] 
h = [(a,b) | a <- pure_xs, b <- pure_f a] 
-- h => [(4,'4'),(5,'5'),(6,'6')] 

グレート。今度は少し異なる2つの式、monadic_fmonadic_xsを取りましょう。できるだけhのように見えるように、リスト内包表記を使用してgを構築したいと思います。ソリューションには一連のIOアクションを生成し、sequenceを使用して、IOモナドにタイプ[(Int,Char)]のリストを生成するという感覚があります。

monadic_xs :: IO [Int] 
monadic_xs = return [1,2,3] 

monadic_f :: Int -> IO String 
monadic_f a = return (show a) 

g :: IO [(Int,Char)] 
g = undefined -- how to make `g` function look 
       -- as similar to `h` function as possible, i.e. using list comprehension? 
-- g => IO [(4,'4'),(5,'5'),(6,'6')] 

答えて

10

これを書くための自然な方法は

do xs <- monadic_xs 
    ys <- mapM monadic_f xs 
    return (zip xs ys) 

だろう。しかし、我々はモナドの値を抽出するためにそこに(>>=)バインドを必要とするので、我々はリスト内包に自然にそれを翻訳することはできません。モナド変圧器は、これらの効果を織り交ぜる道になります。 transformersListT monad transformer-even though it's not actually a monad transformerを調べてみましょう。

newtype ListT m a = ListT { runListT :: m [a] } 

listT_xs :: ListT IO Int 
listT_xs = ListT monadic_xs 

listT_f :: Int -> ListT IO String 
liftT_f = ListT . fmap return . monadic_f 

>>> runListT $ do { x <- listT_xs; str <- listT_f x; return (x, str) } 
[(1,"1"),(2,"2"),(3,"3")] 

だからそれは動作するように、我々はリスト内包形式でそれを書くためにMonadComprehensionsをオンにすることができます表示されます。あなたは私が考えることができるよう、純粋なバージョンを取得する結果約同様だが、それはいくつかの危険な欠陥を持っている

>>> runListT [ (x, str) | x <- listT_xs, str <- listT_f x ] 
[(1,"1"),(2,"2"),(3,"3")] 

。まず、モナド変圧器の法則が破られて直感的ではないListTを使用しています。次に、リストのモナド効果のほんの一部を使用しています。通常、リストには、ジップ。

listT_g :: Int -> ListT IO String 
listT_g = ListT . fmap (replicate 3) . monadic_f 

>>> runListT [ (x, str) | x <- listT_xs, str <- listT_g x ] 
[(1,"1"),(1,"1"),(1,"1"),(2,"2"),(2,"2"),(2,"2"),(3,"3"),(3,"3"),(3,"3")] 

これらの問題を解決するには、pipesを試してみるとよいでしょう。あなたはそこに "正しい"解決策を得ますが、それはリストの理解のようにほとんど見えません。