Haskell构造函数作为函数的变量

我有一个类型,其中有几个构造函数包装了另一种类型;让我们使用下面的例子(实际上我有很多构造函数):

data New a = A a | B a

现在我需要一个函数fun :: (a -> b) -> New a -> b,它将第一个参数应用于f :: a -> b包装在x :: New a. 我可以通过模式匹配来做到这一点:

fun f (A v) = f v
fun f (B v) = f v

这一点都不优雅!看起来我应该可以做类似的事情fun f (_ v) = f v,但是 GHC 给了我Parse error in pattern.

同样,我想要一个con :: New a -> (a -> New a)返回构造函数的函数。同样,我可以模式匹配:

con (A _) = A
con (B _) = B

将这些联合起来的明显模式是con (x _) = x,但这会引发另一个Parse error in pattern: x

问题

  1. 是否有一种更短、更优雅的方式来定义funcon合并案例?
  2. 为什么 GHC 反对这些模式?
  3. 我想在这里做一些禁忌吗?

注意:我接受过正规的数学培训,但我是自学编程的。我对haskell--sorry 如果这个问题有一个明显的、微不足道的答案也有点陌生。我尝试了很多谷歌搜索,但没有任何成功。

回答

严格来说,GHC 没有技术上的理由不允许这种事情,除非它只有在所有构造函数都具有相同类型的参数时才起作用——否则你不能对它们应用相同的函数。

这给了我们一个洞见:大多数情况下,可区分联合构造函数具有不同类型的参数,例如data Thing = Text String | Number Int,即使类型恰好相同,这通常也只是巧合,而参数实际上具有不同的含义,例如data Heisenberg = Velocity Vector2D | Position Vector2D,这样即使技术上可行,对它们应用相同的功能也是没有意义的。

这就是歧视性工会的预期含义。构造函数应该代表语义上不同种类的事物。

这就是为什么 GHC 不支持这种语法的原因,即使类型匹配:它超出了预期的用例,而且大多数时候它是无用的,即使它可能在某些非常狭窄的领域有用。


但是从您对所需用例的描述来看,您似乎正在尝试表达完全不同的东西:它看起来像a两者中的A a并且B a旨在表示相同的事物,而AB仅用作“标签”,以表达值的某些属性,该属性不是值本身固有的。例如,a可以是气球的大小,而AB可以代表气球可以具有的两种不同颜色。

如果这确实是您要表达的内容,那么更好的模型是对标签进行编码,而不是尝试硬塞 DU 构造函数来表示它们,然后将标签与记录中的值组合起来:

data NewTag = A | B
data New a = New { tag :: NewTag, value :: a }

根据这个定义,无论是funcon变得简单:

fun :: (a -> b) -> New a -> b
fun f n = f $ value n

con :: NewTag -> a -> New a
con tag value = New { tag = tag, value = value }

或者如果你喜欢那种事情,那就不用点了:

fun :: (a -> b) -> New a -> b
fun f = f . value 

con :: NewTag -> a -> New a
con = New


以上是Haskell构造函数作为函数的变量的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>