简体   繁体   English

Haskell中的Unsequence Monad函数

[英]Unsequence Monad function within Haskell

I'm having some real trouble designing the counterfunction of Haskell's sequence function, which Hoogle tells me doesn't yet exist. 我在设计Haskell sequence函数的反函数时遇到了一些麻烦,Hoogle告诉我这个函数还不存在。 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.)

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: 我实际上并不知道这是否可能,因为我会在某个时候逃避monad,但我已经开始了,虽然我不知道如何为这个递归函数设置断点:

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

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? 我知道当这里的m等于return []时我需要一个断点,但并不是所有monad都有Eq实例,所以我怎么能这样做呢? Is this even possible? 这甚至可能吗? If so, why and why not? 如果是这样,为什么不呢? Please tell me that. 请告诉我。

You can't have an unsequence :: (Monad m) => m [a] -> [ma] . 你不能没有unsequence :: (Monad m) => m [a] -> [ma] The problem lies with lists: you can't be sure how may elements you are going to get with a list, and that complicates any reasonable definition of unsequence . 问题在于列表:您无法确定列表中的元素是如何获得的,这会使任何合理的unsequence定义变得复杂。

Interestingly, if you were absolutely, 100% sure that the list inside the monad is infinite, you could write something like: 有趣的是,如果你是绝对的, 100%确定monad中的列表是无限的,你可以这样写:

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

And it would work! 它会工作!

Also imagine that we have a Pair functor lying around. 还想象一下我们周围有一个Pair仿函数。 We can write unsequencePair as 我们可以写unsequencePair作为

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

In general, it turns out you can only define unsequence for functors with the property that you can always "zip" together two values without losing information. 一般来说,事实证明你只能为仿函数定义unsequence ,你可以随时将两个值“压缩”在一起而不会丢失信息。 Infinite lists (in Haskell, one possible type for them is Cofree Identity ) are an example. 无限列表(在Haskell中,一种可能的类型是Cofree Identity )就是一个例子。 The Pair functor is another. Pair仿函数是另一个。 But not conventional lists, or functors like Maybe or Either . 但不是常规列表,也不是像MaybeEither这样的仿函数。

In the distributive package, there is a typeclass called Distributive that encapsulates this property. distributive包中,有一个名为Distributive的类型类封装了这个属性。 Your unsequence is called distribute there. 你的unsequence被称为distribute在那里。

It is indeed not possible to create an unsequence function using monads alone. 确实不可能单独使用monad来创建一个unsequence函数。 The reason is: 原因是:

  1. You can safely and easily create a monadic structure from a value using return . 您可以使用return从值安全轻松地创建monadic结构。
  2. However, it is not safe to remove a value from a monadic structure. 但是,从monadic结构中删除值是不安全的。 For example you can't remove an element from an empty list (ie a function of the type [a] -> a is not safe). 例如,您无法从空列表中删除元素(即类型[a] -> a函数不安全)。
  3. Hence we have a special function (ie >>= ) which safely removes a value from a monadic structure (if one exists), processes it and returns another safe monadic structure. 因此,我们有一个特殊的函数(即>>= ),它可以安全地从monadic结构中删除一个值(如果存在),处理它并返回另一个安全的monadic结构。

Hence it is safe to create a monadic structure from a value. 因此,从值创建monadic结构是安全的。 However it is not safe to remove a value from a monadic structure. 但是从monadic结构中删除值是不安全的。

Suppose we had a function extract :: Monad m => ma -> a which could “safely” remove a value from a monadic structure. 假设我们有一个函数extract :: Monad m => ma -> a ,它可以“安全地”从monadic结构中删除一个值。 We could then implement unsequence as follows: 然后我们可以实现如下的unsequence

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

However, there's no safe way to extract a value from a monadic structure. 但是,没有一种安全的方法可以从monadic结构中提取值。 Hence unsequence [] and unsequence Nothing will return undefined . 因此unsequence []unsequence Nothing将返回undefined

You can however create an unsequence function for structures that are both monadic and comonadic. 但是,您可以创建一个unsequence为均为一元和comonadic结构功能。 A Comonad is defined as follows: 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

A comonadic structure is the opposite of a monadic structure. 一个共同结构与一元结构相反。 In particular: 特别是:

  1. You can safely extract a value from a comonadic structure. 您可以安全地从comonadic结构中提取值。
  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. 但是,您无法从值安全地创建新的comonadic结构,这就是duplicate函数从值安全地创建新的comonadic结构的原因。

Remember that the definition of unsequence required both return and extract ? 请记住, unsequence的定义需要returnextract吗? You can't safely create a new comonadic structure from a value (ie comonadic structures don't have return ). 您无法从值安全地创建新的comonadic结构(即,comonadic结构没有return )。 Hence the unsequence function is defined as follows: 因此, unsequence函数定义如下:

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

Interestingly sequence works on simply monadic structures. 有趣的是, sequence适用于单一结构。 So via intuition you might assume that unsequence works on simply comonadic structures. 所以,通过直觉,你可能会认为, unsequence适用于只是comonadic结构。 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. 但事实并非如此,因为您需要首先从comonadic结构中提取列表,然后将列表的每个元素放入monadic结构中。

The general version of the unsequence function converts a comonadic list structure to a list of monadic structures: 在常规版本unsequence函数转换comonadic列表结构一元结构的列表:

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

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: 另一方面, sequence函数仅适用于monadic结构,因为您只是通过链接所有monad将monadic结构列表折叠成monadic列表结构:

import Control.Monad (liftM2)

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

Hope that helps. 希望有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM