簡體   English   中英

Haskell中的Unsequence Monad函數

[英]Unsequence Monad function within Haskell

我在設計Haskell sequence函數的反函數時遇到了一些麻煩,Hoogle告訴我這個函數還不存在。 這是它的行為方式:

ghci> sequence [Just 7, Just 8, Just 9]
Just [7,8,9]
ghci> sequence [getLine, getLine, getLine]
hey
there
stack exchange
["hey","there","stack exchange"] :: IO [String]

我的問題是制作這樣的函數:

unsequence :: (Monad m) => m [a] -> [m a]

所以它的行為如下:

ghci> unsequence (Just [7, 8, 9])
[Just 7, Just 8, Just 9]
ghci> sequence getLine
hey
['h','e','y'] :: [IO Char] --(This would actually cause an error, but hey-ho.)

我實際上並不知道這是否可能,因為我會在某個時候逃避monad,但我已經開始了,雖然我不知道如何為這個遞歸函數設置斷點:

unsequence m = (m >>= return . head) : unsequence (m >>= return . tail)

我知道當這里的m等於return []時我需要一個斷點,但並不是所有monad都有Eq實例,所以我怎么能這樣做呢? 這甚至可能嗎? 如果是這樣,為什么不呢? 請告訴我。

你不能沒有unsequence :: (Monad m) => m [a] -> [ma] 問題在於列表:您無法確定列表中的元素是如何獲得的,這會使任何合理的unsequence定義變得復雜。

有趣的是,如果你是絕對的, 100%確定monad中的列表是無限的,你可以這樣寫:

unsequenceInfinite :: (Monad m) => m [a] -> [m a]
unsequenceInfinite x = fmap head x : unsequenceInfinite (fmap tail x)

它會工作!

還想象一下我們周圍有一個Pair仿函數。 我們可以寫unsequencePair作為

unsequencePair :: (Monad m) => m (Pair a) -> Pair (m a)
unsequencePair x = Pair (fmap firstPairElement x) (fmap secondPairElement x)

一般來說,事實證明你只能為仿函數定義unsequence ,你可以隨時將兩個值“壓縮”在一起而不會丟失信息。 無限列表(在Haskell中,一種可能的類型是Cofree Identity )就是一個例子。 Pair仿函數是另一個。 但不是常規列表,也不是像MaybeEither這樣的仿函數。

distributive包中,有一個名為Distributive的類型類封裝了這個屬性。 你的unsequence被稱為distribute在那里。

確實不可能單獨使用monad來創建一個unsequence函數。 原因是:

  1. 您可以使用return從值安全輕松地創建monadic結構。
  2. 但是,從monadic結構中刪除值是不安全的。 例如,您無法從空列表中刪除元素(即類型[a] -> a函數不安全)。
  3. 因此,我們有一個特殊的函數(即>>= ),它可以安全地從monadic結構中刪除一個值(如果存在),處理它並返回另一個安全的monadic結構。

因此,從值創建monadic結構是安全的。 但是從monadic結構中刪除值是不安全的。

假設我們有一個函數extract :: Monad m => ma -> a ,它可以“安全地”從monadic結構中刪除一個值。 然后我們可以實現如下的unsequence

unsequence :: Monad m => m [a] -> [m a]
unsequence = map return . extract

但是,沒有一種安全的方法可以從monadic結構中提取值。 因此unsequence []unsequence Nothing將返回undefined

但是,您可以創建一個unsequence為均為一元和comonadic結構功能。 Comonad定義如下:

class Functor w => Comonad w where
    extract   :: w a -> a
    duplicate :: w a -> w (w a)
    extend    :: (w a -> b) -> w a -> w b

    duplicate = extend id
    extend f = fmap f . duplicate

一個共同結構與一元結構相反。 特別是:

  1. 您可以安全地從comonadic結構中提取值。
  2. 但是,您無法從值安全地創建新的comonadic結構,這就是duplicate函數從值安全地創建新的comonadic結構的原因。

請記住, unsequence的定義需要returnextract嗎? 您無法從值安全地創建新的comonadic結構(即,comonadic結構沒有return )。 因此, unsequence函數定義如下:

unsequence :: (Comonad m, Monad m) => m [a] -> [m a]
unsequence = map return . extract

有趣的是, sequence適用於單一結構。 所以,通過直覺,你可能會認為, unsequence適用於只是comonadic結構。 但事實並非如此,因為您需要首先從comonadic結構中提取列表,然后將列表的每個元素放入monadic結構中。

在常規版本unsequence函數轉換comonadic列表結構一元結構的列表:

unsequence :: (Comonad w, Monad m) => w [a] -> [m a]
unsequence = map return . extract

另一方面, sequence函數僅適用於monadic結構,因為您只是通過鏈接所有monad將monadic結構列表折疊成monadic列表結構:

import Control.Monad (liftM2)

sequence :: Monad m => [m a] -> m [a]
sequence = foldr (liftM2 (:)) (return [])

希望有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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