NamedFieldPuns,使用变量名匹配模式

时间:2017-02-26 08:16:38

标签: haskell pattern-matching

*.xlsx

收到错误

{-# LANGUAGE NamedFieldPuns #-}

data Factory = Factory { fId :: Int}
data Link = Link Int Int Double

hasLinkTo :: Factory -> Link -> Bool
hasLinkTo Factory{fId} (Link fId _  _) = True

我知道使用变量可以修复它,

• Conflicting definitions for ‘fId’ Bound at: <source.hs> In an equation for ‘hasLinkTo’

我想要求

  • 编译失败的原因,为了更好地理解模式匹配的工作原理。
  • 是否有任何惯用的方式来编写函数?

例如:如果我想提取到节点hasLinkTo Factory{fId=a} (Link b _ _) = a == b 的链接,我想写这样的东西

i

有没有办法只使用非数字文字上的模式匹配来检查(==)?

connected :: Int -> Link -> (Int, Double) connected i (Link i j d) = (j,d) connected i (Link j i d) = (j,d) 工作正常。但上面的例子不会。

2 个答案:

答案 0 :(得分:2)

Factory{fId}记录双关语只是GHC扩展到Factory{fId=fId}的句法糖。这声明了一个名为fId的变量,其值为fId记录中名为Factory的字段。

此外,模式匹配仅声明变量。它不允许您通过重复相同的名称来比较它们。考虑尝试比较平等:

eq a a = True
eq _ _ = False

这是一个尝试做同样事情的简单例子。但它不会编译。

以同样的方式,编译器会抱怨,因为在执行(Link fId _ _)时声明了两个变量。这是不允许的。相反,您需要使用另一个名称并明确比较两者:

hasLinkTo Factory{fId} (Link fInd' _ _) = fId == fId' 

答案 1 :(得分:2)

Haskell只允许使用线性模式,每个变量最多只能出现一次。我相信这是一个刻意的设计选择。从理论上讲,

case e1 of C x x y -> e2 ; ...

可以自动翻译为

case e1 of C x1 x2 y | x1==x2 -> e2 ; ...

这意味着非线性模式需要对非线性变量类型进行额外的Eq约束。此外,可以认为程序员可能会意外地错误地重用变量,如果我们允许非线性模式,这将被忽略并导致意外的语义。

可能Haskell的设计者认为在模式中添加| x1==x2并不是太麻烦,并且使意图更加明确。

但是,对于数字文字,他们保留了这种翻译。模式

case e1 of K 0 y z -> e2 ; ...

转换为

case e1 of K x y z | x==0 -> e2 ; ...

并且需要Eq。由于0不是变量,我们不再存在非线性模式的问题。

无论如何,惯用的方法是在非线性模式中添加| x1==x2等守卫。 目前您不能仅使用模式匹配。