Haskell pattern matching vector

I'm following an online tutorial on Haskell We define a function to add a two-dimensional vector, represented by tuple pairs of numbers The following is an explicit type declaration that ensures that both inputs are two-dimensional vectors

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

I understand why the following function definition uses pattern matching: it describes the pattern that the input data should conform to

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

Why does the following alternative function definitions not use pattern matching? (FST) and (SND) are guaranteed to work because the input is explicitly declared as a tuple of length 2

What is the difference between the two function definitions?

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

Solution

They are different in severity Suppose we rename them:

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

Addvectorsstrict undefined undefined undefined - only the outer (,) constructor of the result is required to perform pattern matching:

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

But addvectorslazy undefined undefined is (undefined, undefined) – pattern matching is postponed until an element of the result is required

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

Basically, addvectors lazy always returns a tuple whose elements may not be evaluated Addvectorsstrict may not return You can also use deferred pattern matching to get the effect of addvectorslazy:

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

To better understand the evaluation sequence, you can use debug Trace. Trace observe it:

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))

The basic point about evaluation in Haskell is that it is driven by pattern matching using case and functional equations (this is the same as desugar to case)

It doesn't matter in this case, but if your results are never needed, you can write your functions lazily to avoid evaluating expensive calculations, or if you know that some results are always needed, be strict to avoid thunk overhead

In general, it's best to make the fields of data structures strict. Unless you need them to be lazy, and unless you need them to be strict, your functions will become lazy Here you can make a strict pair type to represent your vector:

data Vector a = Vector !a !a
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>