2011-11-03 80 views
19

我是Haskell的新手,希望這個問題不是愚蠢的。「List」是否在Haskell的模式匹配中被特別處理?

我見過這麼多的例子,當我有一個名單,我能夠在列表中個別變量的匹配和綁定「組成元素」:

listSizeDesc :: [a] -> String 
listSizeDesc [] = "Emtpy" 
listSizeDesc (x:xs) = "Something inside" 

不過,我盡力去做如:

foo :: Int -> String 
foo 0 = "Zero" 
foo (n - 1) = "next number is " ++ show n 

它不起作用。

在我看來,(n-1)和(x:xs)都描述了參數如何「創建」並將「組件」綁定到參數。 List匹配的方式是專門爲便於遞歸而設計的嗎?因爲在我看來,這個匹配/參數綁定邏輯不適用於除(:)以外的其他函數。

+13

絕對不是一個愚蠢的問題。這是我作爲新手的理解:列表不是「特殊的」。模式匹配適用於:因爲:是列表的類型構造函數。它適用於類型構造函數,但不適用於一般函數。這項工作如何解釋得很好[這裏在WikiBooks](http://en.wikibooks.org/wiki/Haskell/Pattern_matching) –

+1

只要它被問得好,沒有這樣的事情是一個愚蠢的問題。 – hugomg

+1

簡短回答:No. –

回答

14

列表類型爲「總和型」與構造函數,像這樣:

data List a = 
    cons a (List a) 
    | nil 

你第一個例子是在數據類型的模式匹配(與語法糖:)。

你的第二個例子是整數的模式匹配,它不是數據源的定義。在整數上,使用你的語法沒有模式。如果您編碼與整數數據類型一樣

foo :: Int -> String 
foo 0 = "Zero" 
foo n = "next number is " ++ show (n+1) 

在一個側面說明:

data Nat = Zero | Succ Nat deriving (Show) 

然後你可以使用你的模式匹配,你想開始你可能會寫你的榜樣。

foo :: Nat -> String 
foo Zero = "Zero" 
foo [email protected](p) = "next number is " ++ show(n) 

這裏Succ(p)起着n-1的作用模式。

+0

好例子!一切都對我有意義:D非常感謝 –

+2

最後一個例子是倒退。爲了匹配OP想要的內容,模式應該是'n',函數應該顯示'Succ n'。 – jwodder

3
moo :: Int -> String 
moo 0 = "Zero" 
moo n = "next number is " ++ show (n + 1) 

n - 1是一個普通的函數應用程序,而不是一個模式。 +曾經有一個例外,這可能是你正在通過的模型。你可以寫類似

goo :: Int -> String 
goo 0 = "Zero" 
goo (n+1) = "previous number is " ++ show n 
hugs

;你仍然可以用ghc做到這一點,如果包括編譯

{-#LANGUAGE NPlusKPatterns#-} 
+5

順便說一句,那些'NPlusKPatterns'已被棄用,因爲它們混淆了許多程序員。小心使用!另外,AFAIK他們只匹配正數。 – fuz

+0

是的,這是我的觀點,我想不清楚。 – applicative

18

您遇到的問題是,模式只匹配可與數據構造。數據構造器本質上非常簡單;它只是獲取數據值並將它們以某種結構分組在一起。例如,data Foo = Bar a b只需要兩條數據,並將它們組合在Foo標籤下。您在第一個示例中使用的(:)函數不僅僅是一個函數;它是一個數據構造函數。它通過向左參數添加左參數來構造新列表。

現在,模式匹配只是做與這個過程相反的。它解構一個數據類型。當您在模式中編寫(x:xs)時,您將提取構造函數最初縫合在一起的兩段數據。因此,所有模式匹配都會提取構造函數先前拼接在一起的數據。

有一個例外:n + k模式。在Haskell98中,您可以使用形式(n + k)的模式。這是一個任意的例外,最近被刪除。如果你願意,如果你包含NPlusKPatterns語言編譯指示,你仍然可以使用它。

+0

很棒的回答。儘管由於給出了直觀的例子,我將「接受」作爲另一個答案,但這個答案無疑同樣重要。我希望我能同時接受2個答案,因爲我認爲這兩個答案都是對彼此很好的讚美。 –

5

已經有一些很好的答案,所以我不會打擾主要問題。這是而不是它的最佳用途,但你想要做的事情可以用view patterns完成。

{-# LANGUAGE ViewPatterns #-} 

foo :: Int -> String 
foo 0 = "Zero" 
foo (pred -> n) = "Next number is " ++ show n 
4

只是把它儘可能簡單:
名單字面上是一系列級聯的。數字可能等於算術運算的結果。區別在於a : b的結果只是a : b


的詳細信息:

列表和(:)是不是一個特例,在所有。讓我們把我們自己:

data List2 a = End    -- equivalent of "[]" 
      | Cat a (List2 a) -- non-infix ":" 
    deriving (Show) 

所以[1, 2, 3],這== (1 : (2 : (3 : []))),會被寫成:

a = Cat 1 (Cat 2 (Cat 3 End)) 

就像模式匹配(x:xs),我們可以模式匹配列表2:

newTail End = End 
newTail (Cat _ x) = x 

測試:

*Main> tail [1,2,3] 
[2,3] 
*Main> newTail a 
Cat 2 (Cat 3 End)