列表理解很容易理解.请看h
以下定义.它使用pure_xs
类型[Int]
和pure_f
类型Int -> String
,在列表推导中使用两者.
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')]
大.现在采取两个略有不同的表达,monadic_f
并且monadic_xs
.我想g
使用列表推导构建,看起来尽可能相似h
.我有一种感觉,解决方案将涉及生成一系列IO操作,并使用sequence
生成[(Int,Char)]
IO monad 中的类型列表.
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')]
J. Abrahamso.. 10
写这个的自然方式是
do xs <- monadic_xs ys <- mapM monadic_f xs return (zip xs ys)
但是我们无法将其自然地转换为列表理解,因为我们需要(>>=)
在那里绑定以提取monadic值.Monad变形金刚将是交织这些效果的途径.让我们来看看transformers
ListT
monad变压器 - 即使它实际上并不是monad变压器.
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效应的一小部分---通常列表将采用笛卡尔积,而不是zip .
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
.你会在那里得到"正确的"解决方案,尽管它看起来不像列表理解那么多.
写这个的自然方式是
do xs <- monadic_xs ys <- mapM monadic_f xs return (zip xs ys)
但是我们无法将其自然地转换为列表理解,因为我们需要(>>=)
在那里绑定以提取monadic值.Monad变形金刚将是交织这些效果的途径.让我们来看看transformers
ListT
monad变压器 - 即使它实际上并不是monad变压器.
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效应的一小部分---通常列表将采用笛卡尔积,而不是zip .
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
.你会在那里得到"正确的"解决方案,尽管它看起来不像列表理解那么多.