本文介绍了Haskell 中的 Unsequence Monad 函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在设计 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:

  1. 您可以使用 return 从值中安全轻松地创建一元结构.
  2. 然而,从 monadic 结构中删除一个值是不安全的.例如,您不能从空列表中删除元素(即 [a] -> a 类型的函数是不安全的).
  3. 因此,我们有一个特殊的函数(即 >>=),它可以安全地从 monadic 结构(如果存在)中删除一个值,对其进行处理并返回另一个安全的 monadic 结构.莉>
  1. You can safely and easily create a monadic structure from a value using return.
  2. 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).
  3. 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:

  1. 您可以安全地从共调结构中提取值.
  2. 但是,您不能安全地从一个值创建一个新的 comonadic 结构,这就是 duplicate 函数安全地从一个值创建一个新的 comonadic 结构的原因.
  1. You can safely extract a value from a comonadic structure.
  2. 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 的定义同时需要returnextract 吗?你不能安全地从一个值中创建一个新的 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 函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-17 15:58