List Haskell中的非序列单子函数

List Haskell中的非序列单子函数,list,function,haskell,monads,reverse,List,Function,Haskell,Monads,Reverse,我在设计Haskell的序列函数的反函数时遇到了一些实际问题,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] 我的问题是生成这样的函数:

我在设计Haskell的
序列
函数的反函数时遇到了一些实际问题,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.)
因此,它的行为如下所示:

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
实例,那么我该怎么做呢?这可能吗?如果是,为什么?请告诉我。

你不能有一个
反序列::(Monad m)=>m[a]->[ma]
。问题在于列表:您无法确定如何使用列表获取元素,这使得
取消序列的合理定义变得复杂

有趣的是,如果你是绝对的,100%确定monad中的列表是无限的,你可以这样写:

unsequenceInfinite :: (Monad m) => m [a] -> [m a]
unsequenceInfinite x = fmap head x : unsequenceInfinite (fmap tail x)
这会有用的

还假设我们有一对
函子。我们可以将
unsequencePair
编写为

unsequencePair :: (Monad m) => m (Pair a) -> Pair (m a)
unsequencePair x = Pair (fmap firstPairElement x) (fmap secondPairElement x)
一般来说,您只能为具有始终可以“压缩”两个值而不丢失信息的属性的函子定义
取消序列
。无限列表(在Haskell中,一种可能的类型是)就是一个例子。
函子是另一个。但不是传统的列表,或者像
这样的函数可能
或者
或者


在包中,有一个名为
Distributive
的typeclass封装了此属性。您的
unsequence
在那里被称为
distribute

确实不可能单独使用monad创建
unsequence
函数。原因是:

  • 您可以使用
    return
    从值安全轻松地创建一元结构
  • 但是,从一元结构中删除值是不安全的。例如,不能从空列表中删除元素(即
    [a]->a
    类型的函数不安全)
  • 因此,我们有一个特殊的函数(即
    >=
    ),它可以安全地从一元结构(如果存在)中删除一个值,处理它并返回另一个安全的一元结构
  • 因此,从一个值创建一元结构是安全的。但是,从一元结构中删除值是不安全的

    假设我们有一个函数
    extract::Monad m=>ma->a
    ,它可以“安全地”从一元结构中删除一个值。然后,我们可以按如下方式实现
    unsequence

    unsequence :: Monad m => m [a] -> [m a]
    unsequence = map return . extract
    
    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
    
    unsequence :: (Comonad m, Monad m) => m [a] -> [m a]
    unsequence = map return . extract
    
    然而,没有安全的方法从一元结构中提取值。因此,
    unsequence[]
    unsequence Nothing
    将返回
    undefined

    但是,您可以为一元和共元结构创建一个
    unsequence
    函数。
    Comonad
    的定义如下:

    unsequence :: Monad m => m [a] -> [m a]
    unsequence = map return . extract
    
    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
    
    unsequence :: (Comonad m, Monad m) => m [a] -> [m a]
    unsequence = map return . extract
    
    共元结构是一元结构的对立面。特别是:

  • 您可以安全地从comonadic结构中提取值
  • 但是,您无法从值安全地创建新的comonadic结构,这就是为什么
    duplicate
    函数从值安全地创建新的comonadic结构的原因
  • 请记住,
    unsequence
    的定义既需要
    返回
    也需要
    提取
    ?无法从值安全地创建新的comonadic结构(即comonadic结构没有
    返回值
    )。因此,
    unsequence
    函数定义如下:

    unsequence :: Monad m => m [a] -> [m a]
    unsequence = map return . extract
    
    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
    
    unsequence :: (Comonad m, Monad m) => m [a] -> [m a]
    unsequence = map return . extract
    
    有趣的是,
    序列
    只适用于一元结构。因此,通过直觉,你可能会认为,
    unsequence
    只适用于共元结构。但是它不是这样的,因为您需要首先从comonadic结构中提取列表,然后将列表的每个元素放入一元结构中

    unsequence
    函数的通用版本将一个共元列表结构转换为一元结构列表:

    unsequence :: (Comonad w, Monad m) => w [a] -> [m a]
    unsequence = map return . extract
    
    另一方面,
    sequence
    函数只在一元结构上工作,因为您只是通过链接所有的单子将一元结构列表折叠成一元列表结构:

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

    希望有帮助。

    看看为什么不能做一般的事情,考虑一些类似“代码> DO { B”的问题。当使用WordWordMad时,我会发现使用“<代码>不连续的< /代码>的问题。它使所有的状态都消失了。如果有一种方法来实现它,那么STAT从原来的一个元素复制到每个列表元素?后续问题。