Rob*_*art 9 haskell list-comprehension
列表理解很容易理解.请看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')]
Run Code Online (Sandbox Code Playgroud)
大.现在采取两个略有不同的表达,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')]
Run Code Online (Sandbox Code Playgroud)
J. *_*son 10
写这个的自然方式是
do xs <- monadic_xs
ys <- mapM monadic_f xs
return (zip xs ys)
Run Code Online (Sandbox Code Playgroud)
但是我们无法将其自然地转换为列表理解,因为我们需要(>>=)
在那里绑定以提取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")]
Run Code Online (Sandbox Code Playgroud)
所以这似乎工作,我们可以打开MonadComprehensions
以列表理解格式编写它.
>>> runListT [ (x, str) | x <- listT_xs, str <- listT_f x ]
[(1,"1"),(2,"2"),(3,"3")]
Run Code Online (Sandbox Code Playgroud)
这与我能想到的纯版本的结果类似,但它有一些危险的缺陷.首先,我们使用的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")]
Run Code Online (Sandbox Code Playgroud)
要解决这些问题,您可能需要进行试验pipes
.你会在那里得到"正确的"解决方案,尽管它看起来不像列表理解那么多.