Haskell 如何将失败的计算转换为成功的计算,反之亦然

Haskell 如何将失败的计算转换为成功的计算,反之亦然,haskell,typeclass,alternative-functor,monadplus,Haskell,Typeclass,Alternative Functor,Monadplus,这很可能是一个寻找问题的解决方案。。。如果是这样,我请求你的原谅 可能的实施: class Switch' f where switch :: f a -> f () instance Switch' [] where switch [] = [()] switch (_:_) = [] instance Switch' Maybe where switch Nothing = Just () switch (Just _) = Nothing 这

这很可能是一个寻找问题的解决方案。。。如果是这样,我请求你的原谅

可能的实施:

class Switch' f where
  switch :: f a -> f ()

instance Switch' [] where
  switch []     = [()]
  switch (_:_)  = []

instance Switch' Maybe where
  switch Nothing   = Just ()
  switch (Just _)  = Nothing
这种解释是:如果计算成功,就让它失败;给出一个失败的计算,让它成为一个成功的。我不确定,但这似乎有点像MonadPlus的反面。。。如果你眯起眼睛真的很难

这个概念是否有标准的typeclass或其他实现?如果有的话,基础数学是什么样子的(例如,这是一个半群,一个循环,等等)


我有一个通用的解决方案,但它只能用于遵守法律的
MonadPlus
实例(这可能只是一个必要条件,而不是充分条件):

它对我也有用

(对于列表,它总是返回
[()]
,但是,我要说的是,这个定义不适用于任何左分布。)

对于
Applicative
s,不可能用这种方式定义它,因为
开关
检查
的值为零,而应用程序不能这样做。(以及,
MonadPlus
满足左捕捉规则
应用性
法则的实例。)


不管怎样,看看
是否切换是很有趣的。(switch::m()->m())=id
适用于这个定义。

我找到了一个完全不同的答案,那就是。它的定义是:

反转逻辑计算。如果
m
至少有一个值成功,
lnot
m
失败。如果
m
失败,则
lnot m
使值
()
成功


我相信这正是你想要的。

switch
几乎是二阶元素——它几乎是自反的,在
switch.switch.switch
=
switch.switch
中。它最终会生成重复的轨道(虽然“最终”是正确的词,但当提到等待1次迭代时,它听起来很长)<代码>开关。开关是幂等的。这就是我刚才想到的所有关于switch的数学问题。
[()]
为什么返回才是正确的,而不是说,
[(),()…]
?这是
返回()
,就像另一个例子一样。@AndrewC也许规律是
switch
专门化为
m()->m()
的是一个例子。@PetrPudlák是的,我认为这是最好的表达方式。好电话。由于
switch::switch m=>ma->m()
,我们知道
switch x::m()
,所以我说的所有开关都会自动保持。非常整洁。此外,对合是一个比我使用的更好的术语。@MattFenwick我的错误,我已经纠正了它们。
Eq
约束是不可原谅的,当我的数据结构包含函数或其他不可
Eq
-的东西时,我该怎么办?@MattFenwick不确定。这几乎就像我们想要一个
isEmpty
作为
Monoid
/
替代品。或者一些类型类,让我们做一个“外部Eq”,其中
outereq::fa->fb->Bool
是的,看起来像这样。谢谢
switch :: (Alternative f, Eq (f a)) => f a -> f ()
switch x | x == empty = pure ()
         | otherwise = empty
switch :: (MonadPlus m, Eq (m a)) => m a -> m ()
switch x | x == mzero = return ()
         | otherwise = mzero
isZero :: (MonadPlus m) => m a -> m Bool
isZero x = (x >> return False) `mplus` return True

switch :: (MonadPlus m) => m a -> m ()
switch x = isZero x >>= \r -> if r then return () else mzero
lnot :: MonadLogic m => m a -> m ()