当前位置: 首页 > 知识库问答 >
问题:

如何在MonadPlus/Alternative中组合并分支

谢璞
2023-03-14

我最近写了

do
  e <- (Left <$> m) <|> (Right <$> n)
  more actions
  case e of
    Left x -> ...
    Right y -> ...

这似乎很尴尬。我知道protolude(以及其他一些包)定义了

-- Called eitherP in parser combinator libraries
eitherA :: Alternative f => f a -> f b -> f (Either a b)

但即便如此,这一切都感觉有点手动。有什么我没见过的收紧它的好模式吗?

共有3个答案

闻人昕
2023-03-14

你或许可以这样做:

do
  let acts = do more actions
  (do x <- m; acts; ...) <|> (do y <- n; acts; ...)

我不知道这对你来说是否更好。

(当然,如果这些更多操作绑定了许多变量,那么这就不会很好地解决问题)

汪兴旺
2023-03-14

这是对这个问题的过度思考,但是。。。

在您的代码中,的每个分支的类型可能是不同的,但它们不会逃出do块,因为它们被的延续“擦除”。

这看起来有点像存在主义。也许我们可以声明一个新类型,它将初始操作与其延续一起打包,并为该新类型提供一个可选的实例。

实际上,我们不必声明它,因为这样一个新类型已经存在于Hackage中:它是kan-扩展中的Coyoneda。

data Coyoneda f a where       
    Coyoneda :: (b -> a) -> f b -> Coyoneda f a  
Alternative f => Alternative (Coyoneda f)
MonadPlus f => MonadPlus (Coyoneda f)

在我们的例子中,“返回值”本身将是一个一元动作m,因此我们想要处理Coyoneda m(ma)类型的值,其中ma是整个do块的类型。

了解所有这些,我们可以定义以下函数:

sandwich :: (Foldable f, MonadPlus m, Monad m) 
         => m x 
         -> f (Coyoneda m (m a)) 
         -> m a
sandwich more = join . lowerCoyoneda . hoistCoyoneda (<* more) . asum 

重新实现原始示例:

sandwich more [Coyoneda m xCont, Coyoneda n yCont]

酆耀
2023-03-14

我只是注意到OP在评论中表达了同样的想法。不管怎样,我还是要发表我的想法。

Coyoneda是一个巧妙的技巧,但对于这个特殊的问题,它有点矫枉过正。我想你所需要的只是常规的旧的延续。

让我们命名这些...s:

do
  e <- (Left <$> m) <|> (Right <$> n)
  more actions
  case e of
    Left x -> fx x
    Right y -> fy y

那么,我们可以这样写:

do
  e <- (fx <$> m) <|> (fy <$> n)
  more actions
  e

这有点微妙——使用很重要

 类似资料:
  • 我试图在R中合并2个数据帧,但我有两个不同的列,带有不同类型的ID变量。有时一行会有其中一列的值,而另一列却没有。我想同时考虑它们,这样,如果一个帧缺少一个列的值,那么将使用另一个列。 我想合并这两个数据帧,得到2行: null 编辑:理想情况下,输出如下所示: 第1行匹配,因为列“first”在两个数据帧中具有相同的值,并且它填充了来自DF2的“second”的值 第2行匹配,因为列“secon

  • 问题内容: 您好,我想基于数组中的唯一项合并数组。 我拥有的对象 在这个totalCells数组中,我有几个这样的对象 现在,我想制作一个数组,在该数组中我可以基于lineNumber进行数组组合。 就像我有一个具有lineNumber属性和cellWidth集合的对象。我可以这样做吗? 我可以遍历每一行并检查行号是否相同,然后按该单元格宽度。有什么办法我可以算吗? 我正在尝试获得这样的输出。 问

  • 问题内容: 我有一个带有4列的(example-)数据框: 我现在想将B,C和D列合并/合并到新的E列,如本例所示: 我在这里发现了一个非常类似的问题,但这在A列的末尾添加了合并的列B,C和D: 感谢帮助。 问题答案: 选项1 使用和 选项2 使用分配和 选项3 最近,我喜欢第3个选项。 使用

  • 问题内容: 我有两个数组。 我需要合并这些数组,并在下拉列表中显示为 我怎么能使用swift.im新手来快速获得此结果,有人可以帮忙吗? 问题答案: 压缩数组并连接结果:

  • 问题内容: 考虑下表, 我如何获得以下结果 尝试过的形式但未获得正确的结果,数学将始终放在Subject_1之下,而Science总是在SUbject_2之下。 问题答案: 使用: 最大限度 通过…分组 SQL>选择名称, 2个最大(subject_1)subject_1, 3个最大(marks_1)个marks_1, 4个MAX(subject_2)subject_2, 5个最大(marks_2

  • 问题内容: 我有一个表的数组列类型: 我想写一个查询,每个标题生成一个数组(理想情况下,它将是一个设置/去重复的数组) 例如 上面的查询当然行不通,但是我想产生2行: 任何帮助或指针将不胜感激(我使用的是Postgres 9.1) 基于Craig的帮助,我得出以下结论(语法略有更改,因为9.1完全按照他的显示抱怨该查询) 问题答案: 自定义汇总 方法1:定义自定义集合。这是我之前写的。 横向查询