假设我的Vector
数据类型定义如下:
data Vector = Vector { x :: Double
, y :: Double
, z :: Double
}
使用成员访问来定义函数是否更常见:
vecAddA v w
= Vector (x v + x w)
(y v + y w)
(z v + z w)
或使用模式匹配:
vecAddB (Vector vx vy vz) (Vector wx wy wz)
= Vector (vx + wx)
(vy + wy)
(vz + wz)
(如果我的任何术语不正确,请道歉。)
答案 0 :(得分:12)
我通常会使用模式匹配,特别是因为你正在使用所有构造函数的参数,并且它们不是很多。此外,在此示例中,这不是问题,但请考虑以下事项:
data Foo = A {a :: Int} | B {b :: String}
fun x = a x + 1
如果您使用模式匹配来处理Foo类型,那么您就是安全的;无法访问不存在的成员。另一方面,如果使用访问器函数,则在此处调用fun (B "hi!")
等一些操作将导致运行时错误。
编辑:虽然当然很可能忘记在某些构造函数上匹配,但模式匹配使得它非常明确,所发生的事情取决于使用的构造函数(您还可以告诉编译器检测并警告您不完整的模式)而函数的使用暗示任何构造函数都是如此,IMO。
最好保存访问器,以用于只想获得一个或几个构造函数(可能很多)参数的情况,并且您知道使用它们是安全的(没有在错误的构造函数上使用访问器的风险,如在示例中。)
答案 1 :(得分:7)
另一个小的“真实世界”论点:一般来说,拥有这样的短记录条目名称并不是一个好主意,因为x
和y
之类的短名称通常最终被用于局部变量。
所以这里的“公平”比较是:
vecAddA v w
= Vector (vecX v + vecX w) (vecY v + vecY w) (vecZ v + vecZ w)
vecAddB (Vector vx vy vz) (Vector wx wy wz)
= Vector (vx + wx) (vy + wy) (vz + wz)
我认为模式匹配在这种类型的大多数情况下都胜出。一些值得注意的例外:
答案 2 :(得分:4)
这是一种审美偏好,因为这两者在语义上是等价的。好吧,我想在一个天真的编译器中,由于函数调用,第一个会慢一些,但我很难相信在现实生活中不会被优化掉。
尽管如此,记录中只有三个元素,因为你无论如何都在使用全部三个元素,并且可能某些对他们的订单有意义,我会使用第二个。第二个(虽然较弱)的论点是,这样你就可以使用合成和分解的顺序,而不是订单和字段访问的混合。
答案 3 :(得分:4)
(提醒,可能是错的。我仍然是Haskell的新手,但这是我的理解)
其他人没有提到的一件事是模式匹配会使其参数中的函数“严格”。 (http://www.haskell.org/haskellwiki/Lazy_vs._non-strict)
要选择使用哪种模式,程序必须在调用函数之前减少WHNF 的参数,而使用record-syntax访问器函数将评估参数 inside 功能。
我无法给出任何具体的例子(仍然是一个新手)但是这可能会产生性能影响,其中大量的“thunk”可以在递归的,非严格的函数中构建。 (这意味着,对于像提取值这样的简单函数,应该没有性能差异。)
(非常欢迎具体例子)
简而言之
f (Just x) = x
实际上是(使用BangPatterns
)
f !jx = fromJust jx
编辑:上面的不是严格的一个很好的例子,因为两者实际上都是严格的定义(f bottom = bottom),只是为了说明我从性能方面的意思。
答案 4 :(得分:2)
作为kizzx2 pointed out,vecAddA
和vecAddB
vecAddA ⊥ ⊥ = Vector ⊥ ⊥ ⊥
vecAddB ⊥ ⊥ = ⊥
要在使用模式匹配时获得相同的语义,必须使用无可辩驳的模式。
vecAddB' ~(Vector vx vy vz) ~(Vector wx wy wz)
= Vector (vx + wx)
(vy + wy)
(vz + wz)
但是,在这种情况下,Vector
的字段应该是严格的,以提高效率:
data Vector = Vector { x :: !Double
, y :: !Double
, z :: !Double
}
对于严格字段,vecAddA
和vecAddB
在语义上是等效的。
答案 5 :(得分:0)
Hackage包vect通过允许匹配如f(Vec3 x y z)和索引来解决这两个问题:
get1 :: Vec3 -> Float
get1 v = _1 v
查找HasCoordinates类。
http://hackage.haskell.org/packages/archive/vect/0.4.7/doc/html/Data-Vect-Float-Base.html