问题描述
我在设计 Haskell 的 sequence
函数的反函数时遇到了一些真正的麻烦,Hoogle 告诉我该函数尚不存在.这是它的行为方式:
I'm having some real trouble designing the counterfunction of Haskell's sequence
function, which Hoogle tells me doesn't yet exist. This is how it behaves:
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]
我的问题是制作这样的函数:
My problem is making a function like this:
unsequence :: (Monad m) => m [a] -> [m a]
所以它的行为是这样的:
So that it behaves like this:
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,但我已经开始了,尽管我不知道如何为这个递归函数设置断点:
I don't actually know if that's possible, because I'd be escaping the monad at some point, but I've made a start, though I don't know how to set a breakpoint for this recursive function:
unsequence m = (m >>= return . head) : unsequence (m >>= return . tail)
我意识到当这里的 m
等于 return []
时我需要一个断点,但并不是所有的 monad 都有 Eq
实例,那我该怎么做呢?这甚至可能吗?如果是这样,为什么和为什么不呢?请告诉我.
I realise that I need a breakpoint when the m
here is equal to return []
, but not all monads have Eq
instances, so how can I do this? Is this even possible? If so, why and why not? Please tell me that.
推荐答案
单独使用 monad 确实不可能创建 unsequence
函数.原因是:
It is indeed not possible to create an unsequence
function using monads alone. The reason is:
- 您可以使用
return
从值中安全轻松地创建一元结构. - 然而,从 monadic 结构中删除一个值是不安全的.例如,您不能从空列表中删除元素(即
[a] -> a
类型的函数是不安全的). - 因此,我们有一个特殊的函数(即
>>=
),它可以安全地从 monadic 结构(如果存在)中删除一个值,对其进行处理并返回另一个安全的 monadic 结构.莉>
- You can safely and easily create a monadic structure from a value using
return
. - However, it is not safe to remove a value from a monadic structure. For example you can't remove an element from an empty list (i.e. a function of the type
[a] -> a
is not safe). - Hence we have a special function (i.e.
>>=
) which safely removes a value from a monadic structure (if one exists), processes it and returns another safe monadic structure.
因此从值创建一元结构是安全的.然而,从一元结构中删除一个值是不安全的.
Hence it is safe to create a monadic structure from a value. However it is not safe to remove a value from a monadic structure.
假设我们有一个函数 extract :: Monad m =>m a ->一个可以安全"的
从一元结构中删除一个值.然后我们可以如下实现unsequence
:
Suppose we had a function extract :: Monad m => m a -> a
which could “safely” remove a value from a monadic structure. We could then implement unsequence
as follows:
unsequence :: Monad m => m [a] -> [m a]
unsequence = map return . extract
然而,没有安全的方法从一元结构中提取值.因此 unsequence []
和 unsequence Nothing
将返回 undefined
.
However, there's no safe way to extract a value from a monadic structure. Hence unsequence []
and unsequence Nothing
will return undefined
.
然而,您可以为 monadic 和 comonadic 的结构创建一个 unsequence
函数.Comonad
定义如下:
You can however create an unsequence
function for structures that are both monadic and comonadic. A Comonad
is defined as follows:
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
共调结构与单调结构相反.特别是:
A comonadic structure is the opposite of a monadic structure. In particular:
- 您可以安全地从共调结构中提取值.
- 但是,您不能安全地从一个值创建一个新的 comonadic 结构,这就是
duplicate
函数安全地从一个值创建一个新的 comonadic 结构的原因.
- You can safely extract a value from a comonadic structure.
- However you can't safely create a new comonadic structure from a value, which is why the
duplicate
function safely creates a new comonadic structure from a value.
还记得unsequence
的定义同时需要return
和extract
吗?你不能安全地从一个值中创建一个新的 comonadic 结构(即 comonadic 结构没有 return
).因此 unsequence
函数定义如下:
Remember that the definition of unsequence
required both return
and extract
? You can't safely create a new comonadic structure from a value (i.e. comonadic structures don't have return
). Hence the unsequence
function is defined as follows:
unsequence :: (Comonad m, Monad m) => m [a] -> [m a]
unsequence = map return . extract
有趣的是,sequence
适用于简单的一元结构.因此,通过直觉,您可能会假设 unsequence
仅适用于简单的共调结构.然而事实并非如此,因为您需要先从共组结构中提取列表,然后将列表中的每个元素放入一个一元结构中.
Interestingly sequence
works on simply monadic structures. So via intuition you might assume that unsequence
works on simply comonadic structures. However it not so because you need to first extract the list from the comonadic structure and then put each element of the list into a monadic structure.
unsequence
函数的一般版本将一个 comonadic 列表结构转换为一个 monadic 结构列表:
The general version of the unsequence
function converts a comonadic list structure to a list of monadic structures:
unsequence :: (Comonad w, Monad m) => w [a] -> [m a]
unsequence = map return . extract
另一方面,sequence
函数仅适用于简单的 monadic 结构,因为您只是通过链接所有 monad 将 monadic 结构列表折叠成一个 monadic 列表结构:
On the other hand the sequence
function works on simply monadic structures because you are just folding the list of monadic structures into a monadic list structure by chaining all the monads:
import Control.Monad (liftM2)
sequence :: Monad m => [m a] -> m [a]
sequence = foldr (liftM2 (:)) (return [])
希望有所帮助.
这篇关于Haskell 中的 Unsequence Monad 函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!