这个问题在这里已经有了答案:
Can I match a data constructor wildcard in Haskell?
(2 个回答)
1年前关闭。
我有一个类型,其中有几个构造函数包装了另一种类型;让我们使用下面的示例(实际上我有很多构造函数):
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
.问题 :
fun
和 con
通过合并案件? 备注 : 我接受过正规的数学培训,但我是自学编程的。我对
haskell
也有些陌生--对不起,如果这个问题有一个明显的、微不足道的答案。我已经尝试了很多谷歌搜索,但我没有任何成功。
最佳答案
严格来说,GHC 没有不允许这种事情的技术原因,只是它只有在所有构造函数都具有相同类型的参数时才有效——否则你不能对它们应用相同的函数。
这给了我们一个见解:大多数时候,可区分联合构造函数具有不同类型的参数,例如 data Thing = Text String | Number Int
,即使类型恰好相同,这通常只是巧合,参数实际上有不同的含义,如data Heisenberg = Velocity Vector2D | Position Vector2D
,因此即使技术上可行,对它们应用相同的功能也是没有意义的。
这就是歧视工会的本意。构造函数应该代表语义上不同种类的事物。
这就是为什么 GHC 不支持这种语法的原因,即使类型匹配:它超出了预期的用例,并且大多数时候它是无用的,即使它可能在某些非常狭窄的领域中可能有用。
但是从您对所需用例的描述来看,您似乎在尝试表达一个完全不同的东西:它看起来像 a
在这两个 A a
和 B a
A
表示相同的东西和 B
仅用作“标签”,以表达值的某些属性,这不是值本身所固有的。例如,a
可能是气球的大小,而 A
和 B
可以代表气球可以有的两种不同颜色。
如果这确实是您要表达的内容,那么更好的模型是对标签进行编码,而不是试图硬塞 DU 构造函数来表示它们,然后将标签与记录中的值结合起来:
data NewTag = A | B
data New a = New { tag :: NewTag, value :: a }
有了这个定义,fun
和 con
变得微不足道: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 构造函数作为函数的变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65524588/