这个较弱的半对齐是已知的抽象吗?



我有一个类看起来很像SemiAlign,但不是:

class
( Functor f
)
=> Weakalign f
where
{-# Minimal alignLeft | alignRight #-}
alignLeft :: f a -> f b -> f (Either a b)
alignLeft =
(fmap swap .) . flip alignRight
alignRight :: f a -> f b -> f (Either a b)
alignRight =
(fmap swap .) . flip alignLeft
swap :: Either a b -> Either b a
swap (Left x) =
Right x
swap (Right x) =
Left x

alignLeft将两个结构在冲突时总是取左值,alignRight也这样做,但更倾向于取右值。

都可以用alignWithalign来定义:

alignLeft ::
( Semialign f
)
=> f a -> f b -> f (Either a b)
alignLeft =
alignWith go
where
go (This x) =
Left x
go (That y) =
Right y
go (These x _) =
Left x

但是alignalignWith都不能用alignLeftalignRight来定义。为了说明为什么,考虑以下实例:

instance Weakalign ((,) a) where
alignLeft =
const

感谢Daniel Wagner简化了这个例子。

这是一个完全有效的Weakalign实例,但它不能扩展到遵守Semialign的法律。

这是一个微不足道的例子。您可以考虑使用解析器类型:

data Parser a b
= Parser (a -> [(a, b)])

可以将alignLeft定义为fail through操作,它尝试第一个解析器,只有在失败时才尝试第二个解析器。由于与元组相同的原因,无法将解析器扩展到完整的SemiAlign实例。

我检查了semialign包,它似乎不对应于任何现有的类。然而,它似乎已经存在于某个地方。我想知道它是否存在于另一个我不知道的类似align的包中,或者我可能找错了树,这与align无关。

不管怎样,我更愿意使用现有的库来做这类事情,而不是自己发明。

这是已知的抽象吗?

也许Alternative符合您的需求。像alignLeft这样的东西可以这样实现:

alignLeft :: Alternative f => f a -> f b -> f (Either a b)
alignLeft fa fb = (Left <$> fa) <|> (Right <$> fb)

同样适用于alignRight,只是交换了<|>的参数:

alignRight :: Alternative f => f a -> f b -> f (Either a b)
alignRight fa fb = (Right <$> fb) <|> (Left <$> fa)

它不完全是您指定的类。特别是没有一个真正好的(,)实例(参见Alt)。但它应该满足您对Parser的需求,并且是现有解析器组合器库中非常常用的操作。

最新更新