Haskell中的Monadic列表理解

时间:2013-12-21 20:22:11

标签: haskell list-comprehension

列表理解很容易理解。请查看以下定义中的h。它使用类型为pure_xs的{​​{1}}和类型为[Int]的{​​{1}},并使用列表推导中的两者。

pure_f

大。现在使用两个略有不同的表达式Int -> Stringpure_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')] 。我想使用列表推导构建monadic_f,看起来尽可能与monadic_xs类似。我觉得解决方案将涉及生成一系列IO操作,并使用g在IO monad中生成类型h的列表。

sequence

1 个答案:

答案 0 :(得分:10)

写这个的自然方式是

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

但是我们无法将其自然地转换为列表理解,因为我们需要(>>=)绑定来提取monadic值。 Monad变形金刚将是交织这些效果的途径。我们来看看transformers ListT 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由于它破坏了monad变换器定律而可能不直观,其次,我们只使用列表monadic效应的一小部分---通常列表将采用笛卡尔产品,而不是拉链。

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。你会在那里得到“正确的”解决方案,尽管它看起来不像列表理解那么多。