簡體   English   中英

Haskell中的Monadic列表理解

[英]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_fmonadic_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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM