使用 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 })
,在大多数情况下我感觉更好。
为求和类型编写这样的扩展内容 [Processor
,switch
] 是一项机械工作。所以我想知道:有没有办法让编译器 [GHC] 为我做这件事?或任何其他方式以无意义的方式解构求和类型的值?
注意:我使用 Either
作为示例。 Either
是一个错误的选择,因为许多读者认为我的问题具体是关于 Either
,因此将我指向 either
。我应该使用基础库中没有的求和类型,比如
data Result a b = Fail a | Success b
either
函数允许您指定单独的函数以应用于 Either a b
值中的 Left
和 Right
值:
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)
所以你还没有真正获得任何样板文件。
我不喜欢用模式匹配来解构求和类型的值。由于其尖锐的风格,它对我来说感觉很陌生。
我宁愿为求和类型编写和使用 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 })
,在大多数情况下我感觉更好。
为求和类型编写这样的扩展内容 [Processor
,switch
] 是一项机械工作。所以我想知道:有没有办法让编译器 [GHC] 为我做这件事?或任何其他方式以无意义的方式解构求和类型的值?
注意:我使用 Either
作为示例。 Either
是一个错误的选择,因为许多读者认为我的问题具体是关于 Either
,因此将我指向 either
。我应该使用基础库中没有的求和类型,比如
data Result a b = Fail a | Success b
either
函数允许您指定单独的函数以应用于 Either a b
值中的 Left
和 Right
值:
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)
所以你还没有真正获得任何样板文件。