是否存在Control.Monad加入的内置"反函数"?

wiz*_*zup 1 monads haskell

我用map (:[])分裂String[[Char]],不知道是否有做同样的任何内建的功能存在

In [1]: as = "abcdefg"

In [2]: bs = map (:[]) as
        print bs
        ["a","b","c","d","e","f","g"]

In [3]: import Control.Monad
        cs = join bs
        print cs
        "abcdefg"
Run Code Online (Sandbox Code Playgroud)

这个地图很容易理解,但是,我觉得unjoin . join = id应该存在但是没有在搜索中找到它[a] -> [[a]]

eps*_*lbe 9

TL; DR - 没有这样的功能

首先我想说明:您可以查看您map (:[])map return的名单单子.

解释为什么不存在这样的函数(以合理的方式)

join :: m (m a) -> m a例如,该函数不是单射的

  • join ["abc","def"]
  • join ["ab","cdef"]

有相同的形象.同样的问题是与其他monad:

  • join (Just Nothing)
  • join Nothing

因此通常不存在反函数.

但现在我们知道没有左逆可以存在.

右逆怎么样?

在所有情况下你都有

join . return = id.
Run Code Online (Sandbox Code Playgroud)

我认为 - 但尚未证实,同样适用

join . fmap return = id.
Run Code Online (Sandbox Code Playgroud)

证明.

(join . return) x =  join (return x) -- with the definition of join
                  = return x >>= id -- with monad laws (https://wiki.haskell.org/Monad_laws 
                  = id x
Run Code Online (Sandbox Code Playgroud)

现在我们可以应用eta减少(这只是一个很容易放弃的词x)并获得

join . return = id
Run Code Online (Sandbox Code Playgroud)

注意:id这是m a -> m a!


为了使事情具体化 - 让我们在列表monad中进行此计算[a].

(join . return) "wizzup" = join (return "(^ ? ^)") -- return = \x -> [x]
                                                  -- and join = foldl (++) []
                         = foldl (++) [] ["(^ ? ^)"]
                         = "(^ ? ^)"
Run Code Online (Sandbox Code Playgroud)

这里的版本 (join . fmap return)

(join . fmap return) "(^ ? ^)" = (foldl (++) [] . map (\x -> [x]))"(^ ? ^)"
                              = foldl (++) [] ["(","^"," ? ","^",")"]
                              = "(^ ? ^)"
Run Code Online (Sandbox Code Playgroud)

  • 确实.`return`和`fmap return`都是`join`的_right inverses_. (4认同)

che*_*ner 6

没有unjoin这样的功能unjoin . join == id.假设join x评估为["abc"].现在,是什么xunjoin . join $ x == x?是["a", "b", "c"]吗?是["ab", "c"]吗?是["a", "bc"]吗?或者它是无限多的列表之一["a", "", "bc"](在有限字符串中出现空字符串)?应用join此值后,您将丢失恢复原始值所需的信息.

如果join仅限于一个字符的列表(没有多字符的字符串,没有空字符串)的名单,那么你确实可以定义unjoin这样unjoin . join x == x的,因为unjoin会知道它的输入的每一个元素可以在一个单一的列表被包裹(这是想要map return做在列表monad).


Jon*_*ast 5

根据以下方式编写的三个monad法律join是:

join . return = id
join . fmap return = id
join . join = join . fmap join
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,这可以保证returnjoin您正在寻找的相反.

实际上,map (:[]) = map return = fmap return也是一个正确的反转join.

请注意,这意味着在任何monad中join 都不能有左反,其中return /= fmap return:

假设return /= fmap return,对于一些monad.再有就是一些动作a,这样

return a /= fmap return a
Run Code Online (Sandbox Code Playgroud)

join (return a) = a = join (fmap return a)
Run Code Online (Sandbox Code Playgroud)

你的unjoin,适用于a,必须是 return afmap return a(和可能更多的值),这是一个矛盾.

请注意,对于[]:

return [x, y] = [[x, y]]
fmap return [x, y] = [[x], [y]]
Run Code Online (Sandbox Code Playgroud)

用于IO:

Prelude> return (print "Hello") :: IO (IO ())
Prelude> fmap return (print "Hello") :: IO (IO ())
"Hello"
Run Code Online (Sandbox Code Playgroud)

我能想到的唯一的monad是哪里returnfmap return重合的Identity.