Haskell模式匹配向量

Zhe*_*Koo 3 haskell vector pattern-matching

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

addVectors :: (Num a) => (a, a) -> (a, a) -> (a, a)
Run Code Online (Sandbox Code Playgroud)

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

addVectors (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)  
Run Code Online (Sandbox Code Playgroud)

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

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

addVectors a b = (fst a + fst b, snd a + snd b)
Run Code Online (Sandbox Code Playgroud)

Jon*_*rdy 7

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

> let addVectorsStrict (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)
> let addVectorsLazy a b = (fst a + fst b, snd a + snd b)
Run Code Online (Sandbox Code Playgroud)

addVectorsStrict undefined undefinedundefined- 一旦(,)需要结果的外部构造函数,就执行模式匹配:

> case addVectorsStrict (error "A") (error "B") of (_, _) -> ()
*** Exception: A
Run Code Online (Sandbox Code Playgroud)

addVectorsLazy undefined undefined(undefined, undefined)-the图案匹配将被推迟到的一个元素的结果的被征求.

> case addVectorsLazy (error "A") (error "B") of (_, _) -> ()
()
Run Code Online (Sandbox Code Playgroud)

基本上,addVectorsLazy总是返回一个元组,元素可能会被取消评估.addVectorsStrict可能不会回来.您还可以获得addVectorsLazy使用延迟模式匹配的效果:

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

为了更好地理解评估顺序,您可以使用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))
Run Code Online (Sandbox Code Playgroud)

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

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

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

data Vector a = Vector !a !a
Run Code Online (Sandbox Code Playgroud)