2017-08-10 77 views
3

我正在關注在線tutorial on Haskell。我們定義一個函數來添加二維向量,用數組元組對錶示。以下是顯式類型聲明,確保兩個輸入都是二維向量。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) 
+3

嗯,這只是一種不同的風格定義相同的東西。你的問題到底是什麼? – leftaroundabout

+1

作爲一般建議,我建議儘可能地學習使用模式匹配,至少在初學者級別。'fst,snd'的替代方法是可以的,但是在這裏,我看到太多的初學者使用危險的函數,比如'head,tail,fromJust',當模式匹配更安全時,這往往會導致崩潰,特別是當使用'-Wall'打開警告(強烈推薦)。 – chi

回答

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是一旦外(,)構造的結果是需要進行-the模式匹配:

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

addVectorsLazy undefined undefined(undefined, undefined) -the模式匹配推遲到結果的元素之一被要求。

> 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和函數方程(其中去掉了case)進行模式匹配。

它沒有多大關係在這種情況下,但你可以懶洋洋地寫你的功能,以避免昂貴的評估計算,如果是從來不需要他們的結果,或嚴格避免的thunk的開銷,如果你知道一些結果總是被需要。

在一般情況下,這是一個好主意,使你的數據結構嚴格的領域,除非你需要他們偷懶,讓您功能懶惰,除非你需要他們嚴格。在這裏,你可以製作一個嚴格的對類型來表示你的矢量:

data Vector a = Vector !a !a 
+1

這是真的,但可能太微妙,不適合OP或任何從Google處理此問題的人。 – amalloy

+0

感謝您理解這個問題 - 我沒有說得那麼好,因爲我不認識Haskell!也許我應該遵循[官方教程](https://www.haskell.org/tutorial/patterns.html)。 –