是否有 Control.Monad 的内置 "inverse function" 连接?

Is there a builtin "inverse function" of Control.Monad's join?

我使用 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"

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

TL;DR - 不,没有这样的功能

首先我要注意:您可以将 map (:[]) 视为列表 monad 的 map return

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

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

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

有相同的图像。其他单子也有同样的问题:

  • join (Just Nothing)
  • join Nothing

所以一般来说反函数是不存在的。

但现在我们知道不存在左逆

右逆呢?

在所有情况下你有

join . return = id.

我认为 - 但还没有证明,同样适用于

join . fmap return = id.

证明。

(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

现在我们可以应用 eta 减少(这只是删除 x 的一个花哨的词)并得到

join . return = id

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


为了使事情具体化 - 让我们在列表 monad [a].

中进行计算
(join . return) "wizzup" = join (return "(^ ͜ ^)") -- return = \x -> [x]
                                                  -- and join = foldl (++) []
                         = foldl (++) [] ["(^ ͜ ^)"]
                         = "(^ ͜ ^)"

这里是 (join . fmap return)

的版本
(join . fmap return) "(^ ͜ ^)" = (foldl (++) [] . map (\x -> [x]))"(^ ͜ ^)"
                              = foldl (++) [] ["(","^"," ͜ ","^",")"]
                              = "(^ ͜ ^)"

根据 join 编写的三个 monad 定律是:

join . return = id
join . fmap return = id
join . join = join . fmap join

如您所见,这保证 return 将是您要查找的 join 的倒数。

而且,实际上,map (:[]) = map return = fmap return 也是 join 的右逆。

请注意,这意味着 join 不能 return /= fmap return:

的任何单子中有左逆元

假设 return /= fmap return,对于一些 monad。然后有一些动作 a 这样

return a /= fmap return a

但是

join (return a) = a = join (fmap return a)

你的unjoin应用于a,必须两者return afmap return a(可能更多值),这是矛盾的。

请注意,对于 []

return [x, y] = [[x, y]]
fmap return [x, y] = [[x], [y]]

对于IO

Prelude> return (print "Hello") :: IO (IO ())
Prelude> fmap return (print "Hello") :: IO (IO ())
"Hello"

等我能想到的 returnfmap return 重合的唯一单子是 Identity.

没有函数 unjoin 使得 unjoin . join == id。假设 join x 的计算结果为 ["abc"]。现在,x 是什么使得 unjoin . join $ x == x?是 ["a", "b", "c"] 吗?是 ["ab", "c"] 吗?是 ["a", "bc"] 吗?或者它是无限多个列表之一,如 ["a", "", "bc"](空字符串出现在有限字符串中)?将 join 应用到该值后,您将丢失恢复原始值所需的信息。

如果 join 被限制为只有一个字符的列表列表(没有多字符字符串,没有空字符串),那么您确实可以定义 unjoin 这样 unjoin . join x == x,因为unjoin会知道 它的输入的每个元素都可以包装在一个列表中(这是 want map return 在列表 monad 中做的)。