2013-10-27 106 views
2

A卡都有一個類型和顏色:所有給定項具有財產

data CardType = Spades | Clubs | Diamonds | Hearts 

data CardColor = Black | Red 

cardColor :: CardType -> CardColor 

cardColor card = 
    case card of Spades -> Black 
       Clubs -> Black 
       Diamonds -> Red 
       Hearts -> Red 

type Card = (CardType, CardColor) 

我要檢查所有的卡是否具有相同的顏色:

allTheSameColor :: [Card] -> Bool 

allTheSameColor cardList = ??? 

我不知道,怎麼會我這樣做沒有使用任何庫函數,如filter?但是我們可以自己重新實現它,因爲我希望能夠在深層次的功能層面上理解如何解決這個問題。

+0

你可以看到'過濾器'和朋友是如何在Hackage上實現的;例如這裏是['filter'](http://hackage.haskell.org/package/base-4.6.0.1/docs/src/GHC-List.html#filter)。 –

回答

4

CardColor應該從Eq獲得具有可比性:

data CardColor = Black | Red 
         deriving (Eq) 



allTheSameColor :: [Card] -> Bool 
allTheSameColor [] = True 
allTheSameColor [x] = True 
allTheSameColor (x:y:xs) = if (snd x) == (snd y) then allTheSameColor (y:xs) 
          else False   

更確切地說,你會怎麼說,在列表中的數字是一樣的嗎?不要認爲需要採取哪些步驟或程序來想象,要根據列表元素之間的關係來考慮,您需要弄清楚列表中的元素是否相同。這種關係原來是這樣的:第一個元素==第二個元素AND第二個元素==第三個元素等等直到列表的長度。

+0

這與您如何以歸納方式證明「一系列中的每件商品是前一件商品的兩倍大小」類似。 –

+0

這種關係結果如下:第一個元素==第二個元素AND第二個元素==第三個元素等,直到長度爲'或者第一個元素等於每個元素。 –

3

我總是在我的額外列表功能模塊中的函數是allSameBy。像這樣

allSameBy :: (a -> a -> Bool) -> [a] -> Bool 
allSameBy _ [] = True 
allSameBy eq (x:xs) = all (eq x) xs 

你的問題可以很容易被

allTheSameColor = allSameBy ((==) `on` snd) 

或者(低效率)解決了,你可以定義allSameBy

allSameBy eq xs = length (groupBy eq xs) <= 1 

編輯:或者,如果你不這樣做想要使用任何庫函數(以及稍微不同的語義)

allSameBy _ [] = True 
allSameBy _ [_] = True 
allSameBy eq (x:[email protected](y:_)) = case eq x y of False -> False; True -> allSameBy eq xs 
+0

我喜歡這個想法,除了它使用'on'和'all'或'length'和'groupBy' - 這可能被視爲違反約束「而不使用任何庫函數,例如'filter'」。 –

+0

確實如此,即使我將現有的功能重用爲優點。 :) – augustss

+1

我懷疑用'(==)\'在\'...上調用'allSameBy'是很常見的。可能很高興在''f'上有'allEqualBy f = allSameBy((==)\'),這樣你就可以編寫'allEqualBy color'(看起來很漂亮!)。 –