我在设计 Haskell 的 sequence
的反函数时遇到了一些真正的麻烦。功能,Hoogle 告诉我还不存在。这是它的行为方式:
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]
我的问题是制作这样的功能:
unsequence :: (Monad m) => m [a] -> [m a]
所以它的行为是这样的:
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,但我已经开始了,虽然我不知道如何为这个递归函数设置断点:
unsequence m = (m >>= return . head) : unsequence (m >>= return . tail)
我意识到当
m
时我需要一个断点这里等于 return []
,但并非所有单子(monad)都有 Eq
实例,那么我该怎么做呢?这甚至可能吗?如果是这样,为什么和为什么不呢?请告诉我。
最佳答案
你不能有 unsequence :: (Monad m) => m [a] -> [m a]
.问题在于列表:您无法确定列表将包含多少元素,这会使 unsequence
的任何合理定义变得复杂。 .
有趣的是,如果你绝对是, 100% 确保 monad 中的列表是无限的,您可以编写如下内容:
unsequenceInfinite :: (Monad m) => m [a] -> [m a]
unsequenceInfinite x = fmap head x : unsequenceInfinite (fmap tail x)
它会起作用的!
还假设我们有一个
Pair
周围的仿函数。我们可以写unsequencePair
作为unsequencePair :: (Monad m) => m (Pair a) -> Pair (m a)
unsequencePair x = Pair (fmap firstPairElement x) (fmap secondPairElement x)
一般来说,事实证明你只能定义
unsequence
对于具有属性的仿函数,您可以始终将两个值“压缩”在一起而不会丢失信息。无限列表(在 Haskell 中,一种可能的类型是 Cofree Identity
)就是一个例子。 Pair
仿函数是另一个。但不是传统的列表,也不是像 Maybe
这样的仿函数或 Either
.在
distributive
包中,有一个名为 Distributive
的类型类封装了这个属性。您的 unsequence
被称为 distribute
那里。
关于list - Haskell中的Unsequence Monad函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27342863/