Haskell模式匹配向量

时间:2017-08-10 23:20:15

标签: haskell vector pattern-matching

我正在关注在线tutorial on Haskell。我们定义了一个函数来添加二维向量,由元组对数字表示。以下是显式类型声明,它确保两个输入都是二维向量。

addVectors :: (Num a) => (a, a) -> (a, a) -> (a, a)

我理解为什么以下函数定义使用模式匹配:它描述了输入数据应符合的模式。

addVectors (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)  

为什么以下替代函数定义不使用模式匹配? (fst)和(snd)保证可以正常工作,因为输入显式声明为长度为2的元组。

两个函数定义有什么区别?

addVectors a b = (fst a + fst b, snd a + snd b)

1 个答案:

答案 0 :(得分:7)

他们的严格程度不同。假设我们重命名它们:

> let addVectorsStrict (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)
> let addVectorsLazy a b = (fst a + fst b, snd a + snd b)

addVectorsStrict undefined undefinedundefined - 只要求结果的外(,)构造函数,就会执行模式匹配:

> case addVectorsStrict (error "A") (error "B") of (_, _) -> ()
*** Exception: A

但是addVectorsLazy undefined undefined(undefined, undefined) - 模式匹配延迟到需要结果的元素之一。

> case addVectorsLazy (error "A") (error "B") of (_, _) -> ()
()

基本上,addVectorsLazy总是返回一个元组,其元素可能未被评估。 addVectorsStrict可能无法返回。您还可以使用惰性模式匹配获得addVectorsLazy的效果:

> let addVectorsAlsoLazy ~(x1, y1) ~(x2, y2) = (x1 + x2, y1 + y2)
> case addVectorsAlsoLazy (error "A") (error "B") of (_, _) -> ()
()

为了更好地理解评估顺序,您可以使用Debug.Trace.trace

进行观察
addVectors
  (trace "first tuple evaluated"
    (trace "x1 evaluated" 1, trace "y1 evaluated" 2))
  (trace "second tuple evaluated"
    (trace "x2 evaluated" 3, trace "y2 evaluated" 4))

关于Haskell中评估的基本要点是,它是由使用case和函数方程(desugar to case)的模式匹配驱动的。

在这种情况下并不重要,但你可以懒散地编写你的函数,以避免在不需要结果的情况下评估昂贵的计算,或者如果你知道某些结果会严格避免thunk的开销总是需要。

一般来说,最好让数据结构的字段严格,除非你需要它们是懒惰的,并且除非你需要它们,否则你的函数是懒惰的要严格。在这里,您可以使用严格的对类型来表示您的向量:

data Vector a = Vector !a !a