[英]Monadic list comprehension in Haskell
列表理解很容易理解。 在以下定義中查看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
生成IO monad中的[(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')]
寫這個的自然方式是
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效應的一小部分---通常列表將采用笛卡爾積,而不是壓縮。
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
。 你會在那里得到“正確”的解決方案,盡管它看起來不像列表理解那么多。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.