使用 GHC 进行无点解构

Point-free destructuring with GHC

我不喜欢用模式匹配来解构求和类型的值。由于其尖锐的风格,它对我来说感觉很陌生。 我宁愿为求和类型编写和使用 switch 函数。

我的问题一般是关于任何总和类型,但我在 Either 上进行了演示:

data Processor cl cr r = MakeProcessor { l :: cl -> r, r :: cr -> r }

switch :: Processor cl cr r -> Either cl cr -> r
switch p ei = 
    case ei of
        Left x -> l p x
        Right x -> r p x

Either 的扩展:

而不是这个:

map f e = 
    case e of
        Left x -> Left x
        Right x -> Right (f x)

我可以写这个:

map f = switch (MakeProcessor { l : Left, r : f >>> Right })

,在大多数情况下我感觉更好。

为求和类型编写这样的扩展内容 [Processorswitch] 是一项机械工作。所以我想知道:有没有办法让编译器 [GHC] 为我做这件事?或任何其他方式以无意义的方式解构求和类型的值?


注意:我使用 Either 作为示例。 Either 是一个错误的选择,因为许多读者认为我的问题具体是关于 Either,因此将我指向 either。我应该使用基础库中没有的求和类型,比如

data Result a b = Fail a | Success b

either 函数允许您指定单独的函数以应用于 Either a b 值中的 LeftRight 值:

switch p ei = either (l p) (r p) ei

可以直接从两边丢ei得到

switch p = either (l p) (r p)

并且您可以使用 Applicative 函数实例来删除 p:

switch = either <$> l <*> r

对于任意求和类型,您需要提供适当的 catamorphism,这是像 either 这样的函数的奇特名称,它减少了由将类型求和到包装类型。

简短的回答是否定的(尤其是没有模板 Haskell)。

但是,就像函数式编程中的许多结构一样,您可以将其颠倒过来。使用 Church/Scott 编码(当数据类型不是递归时,它们是相同的)。

newtype ChurchEither a b = ChurchEither { switch :: forall c. (a -> c) -> (b -> c) -> c }

其中消除器switch是免费的,因为它是类型的定义,但是你必须自己编写构造函数

left x = ChurchEither (\l r -> l x)
right x = ChurchEither (\l r -> r x)

所以你还没有真正获得任何样板文件。