List Haskell中的非序列单子函数
我在设计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] 我的问题是生成这样的函数:
序列
函数的反函数时遇到了一些实际问题,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
共元结构是一元结构的对立面。特别是:
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从原来的一个元素复制到每个列表元素?后续问题。