2013-02-11 66 views
3

想知道如果我能得到一些幫助寫這個功能。我試圖創建一個函數來反轉列表中的每個「對」。Haskell反轉對

module Invert where 
invert :: [(a,b)] -> [(b,a)] 
invert [(a,b)] = [(b,a)] 

當我進入invert [(3,1) (4,1) (5,1)] ...它應該給我[(1,3) (1,4) (1,5) ...但它給了我......


*Invert> [(3,1) (4,1) (5,1)] 

<interactive>:2:2: 
    The function `(3, 1)' is applied to two arguments, 
    but its type `(t0, t1)' has none 
    In the expression: (3, 1) (4, 1) (5, 1) 
    In the expression: [(3, 1) (4, 1) (5, 1)] 
    In an equation for `it': it = [(3, 1) (4, 1) (5, 1)] 
+0

忘記逗號笑......但它仍然給我「在功能反轉非詳盡模式」 – 2013-02-11 17:18:16

回答

14

由於列表是遞歸數據結構,因此您必須遞歸處理列表才能交換其所有元素,或者使用某些爲您處理的高階函數。如果你定義了

invert [(a,b)] = [(b,a)] 
invert [(a,b)] = [(b,a)] 

它只會轉換單個元素列表,所有其他輸入將失敗並出現錯誤!

試着想想輸入invert gets:它可以是一個空列表或一個非空列表。在非空列表的情況下,可以交換第一個元素並遞歸地轉換其餘元素。

(如果你不想自己反轉invert,只需使用

invert = map swap 

其中swapData.Tuple)來解決這個

+0

謝謝,我明白了!我最後使用了顯式遞歸:) – 2013-02-11 17:41:28

+1

爲了闡明其他人,當你寫'invert [(a,b)] = [(b,a)]'時,你確實在寫'invert((a,b): [])=(b,a):[]',這就是爲什麼該函數僅適用於一個元素的列表。這對於初學者來說是一個頻繁的混淆之處。 – 2013-02-12 01:26:31

3

所以要映射在一個功能列表是(a, b) -> (b, a)。功能(,)有型號b -> a -> (b,a)。所以如果我們翻轉它,我們得到a -> b -> (b, a)。現在,如果我們uncurry ,我們得到(a, b) -> (b, a)

invert = map (uncurry $ flip (,)) 

例如

> map (uncurry $ flip (,)) [(1, "a"), (2, "b")] 
[("a",1),("b",2)] 

順便說一句,你的彭定康匹配不匹配你想要什麼。定義

invert [(a,b)] = [(b,a)] 

說:「在這一個元組匹配列表」。如果你有一個包含多個元組的列表,則匹配將失敗。另外,正如喬什李指出的,你需要在你的列表中的元組之間逗號。

+5

更簡潔地寫成'map swap'。 – 2013-02-11 17:17:29

4

最好的方式,把它分解成更小的問題,無論是和找到解決這些問題的庫函數,或者編寫自己的函數。我總是告訴初學者,這是一個卓越的運動不是試圖去寫這樣invert一個功能只是其中的一部分,因爲你要學習以下三件事情:

  1. 如何分割的問題爲小,可重複使用的部分。
  2. 該語言提供的標準庫函數。
  3. 如何使用遞歸來編寫類似於標準庫中的小型可重用函數。

在這種情況下,我們可以分割問題轉化爲:

  1. 反相個別元組。
  2. 將函數應用於列表的所有元素並收集結果列表。

第二個是剛上列出了常見的map功能,其自帶的標準庫。你可以嘗試編寫你自己的版本;這樣的事情永遠是一個很好的鍛鍊初學者:

map :: (a -> b) -> [a] -> [b] 
map f []  = ... 
map f (x:xs) = ... 

首先,作爲切赫指出,從Data.Tupleswap功能。但是,我們可以很容易地編寫自己:

swap :: (a, b) -> (b, a) 
swap (a, b) = (b, a) 

而現在,當然:

invert :: [(a, b)] -> [(b, a)] 
invert = map swap