Haskell筆記3

1.foldr

foldr::(a->b->b)->b->[a]->b

foldr函數(shù)應(yīng)用在list上,它的功能就像是把list折疊起來一樣,通過使用foldr,最后將list合成一個結(jié)果。它的具體過程是,它只接受一個以兩個參數(shù)的函數(shù),第二個參數(shù)作為函數(shù)的第二個輸入,List中的元素均作為函數(shù)的第一個參數(shù)進行運算,在進行第一次運算后返回的結(jié)果作為下一步的函數(shù)的第二個參數(shù)。

例如

Input:?foldr (+) 5 [1,2,3,4]

Output:?15

具體來看即: 4+5=9 => 3+9 =12 => 2+12 = 14 => 1+14=15

復(fù)雜的例子即:

alternative :: [Integer] -> Integer

alternative = foldr (\x y->if x< 20 then 5*x-3 + y else y) 0

alternative [1,2,3] =21

具體來看即: 3*5-3+0=12=>2*5-3+12=19=>1*5-3+19=21

2.函數(shù)參數(shù),Maybe Type recursion

通常情況下,我們定義一個以List為參數(shù)的函數(shù),即:

f::[Int]->[Int]

f [] = ..

f (x:xs) = ..

單數(shù)如果出于某些原因,我們希望每次提取兩個元素作為參數(shù),那么我們可以具體定義,例如,我們有encode函數(shù)和decode函數(shù):

encode :: [Color] -> [Bit]

? ? ? ? encode []? ? ? ? ? = []

? ? ? ? encode (Red:xs)? ? = O:O:(encode xs)

? ? ? ? encode (Blue:xs)? = O:I:(encode xs)

? ? ? ? encode (Yellow:xs) = I:O:(encode xs)

Color類型中有三個元素,為了節(jié)約Bit起見,我們用兩個Bit表達。那么在decode函數(shù)中,每次必須提取兩個元素,其它不符合條件的皆為Nothing。我們有多種方法,此處介紹兩種:





方案一:

decode :: [Bit] -> Maybe [Color]

decode []= Just []

decode (O:O:xs) =

? case decode xs of

? ? Nothing -> Nothing

? ? Just ys -> Just (Red:ys)

decode (O:I:xs) =

? case decode xs of

? ? Nothing -> Nothing

? ? Just ys -> Just (Blue:ys)

decode (I:O:xs) =

? case decode xs of

? ? Nothing -> Nothing

? ? Just ys -> Just (Yellow:ys)

decode _ = Nothing

列舉所有可以decode為顏色的輸入,然后將其decode為Color然后再翻譯之后的list, 翻譯后會得到一個color類型的list或者Nothing。 這里有一個問題是這個函數(shù)看起來不是那么的完整(non-exhaustive),因為我們沒有列舉[I,I]的情況。為了更好的說明這個函數(shù)的結(jié)構(gòu),我寫出一個相對簡單的decode函數(shù):



data Bit = O | I

? deriving (Eq, Show, Enum, Bounded)

decode::[Bit]->Maybe [Bool]

decode [] = Just []

decode (I:xs) = case decode xs of

? ? ? ? ? ? Nothing -> Nothing

? ? ? ? ? ? Just bs -> Just (True:bs)

decode _ = Nothing

main::IO()

main = print (decode [I,I,I])

注意函數(shù)最后一個定義,它的意思是不管什么輸入,它都將返回Nothing。

此處涉及到Haskell函數(shù)的pattern matching。 Haskell在調(diào)用函數(shù)時,會應(yīng)用第一個可以調(diào)用的條件。 譬如在這個函數(shù)中, 如果我們 decode [],它會返回 Just [], 而不是 Nothing。decode的核心在 decode (I:xs)這一定義中。如果輸入為I打頭的list,那函數(shù)會對去掉I的list再進行decode,它會返回一個list,或者Nothing。如果是Nothing,那么原始的調(diào)用將返回Nothing,若為一個list,那么它會將這個list的append在第一個decode的結(jié)果之后即True:bs。

我們考慮decode [I,I,I]。?

decode [I,I,I] => decode [I,I]=> decode [I] => decode []

此處代表 [I,I,I] 取決于 [I,I]的結(jié)果, [I,I] 取決于 [I],[I] 取決于 []。

而又因為: Just [] -> Just True:[] -> Just True:True:[]

所以最終結(jié)果為: Just (True:bs) = Just (True:True:True:[]) = Just [True,True,True]

而如果是 decode [I,O,I] 的話:

decode [I,O,I] -> decode [O,I] == Nothing

這里在第一步我們有類型 1:xs, 所以會進入第二個case即對后面的內(nèi)容進行decode。而后我們有[O,I],此時將從函數(shù)第一條開始對應(yīng)O:xs類型不是[],也不是I:xs,那么就會進入最后一個定義,decode _ = Nothing。那么此時將直接進入Nothing case,返回了Nothing,原始函數(shù)取得了bs為Nothing的消息后,進入了Nothing case返回了Nothing。此類定義有一個好處就是,在第一次看到O的時候,就會終止繼續(xù)迭代。



回到我們的color decode的函數(shù)中來。通過上述例子我們可以清晰的了解這個函數(shù)的結(jié)構(gòu),它列舉了所有可decode的情況,然后用相同的方法進行迭代,在第一次無法進行decode的情況下就返回Nothing,終止運算。

那么我們可不可以把可decode的情況全部分開來寫,然后直接寫一個decode function去綜合這幾種情況呢?當然可以!

decode :: [Bit] -> Maybe [Color]

decode [] = Just []

decode [O,O] = Just [Red]

decode [O,I] = Just [Blue]

decode [I,O] = Just [Yellow]

decode (a:b:xs) = case decode [a,b] of

? ? ? ? ? ? ? ? Nothing->Nothing

? ? ? ? ? ? ? ? Just c -> case decode xs of

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Nothing -> Nothing

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Just cs -> Just (c++cs)

decode _ = Nothing

我們可以首先把幾種decode的方法寫出來,最后用a:b來泛指這三種情況。但是此處我們要先判斷[a,b]是否可被decode即會不會有[I,I]的情況,然后再看剩余l(xiāng)ist的decode情況--進行迭代。比較神奇的是這種方式運行的結(jié)果會比上一種慢一些..





方案二:

decode :: [Bit] -> Maybe [Color]

decode []= Just []

decode (O:O:xs) = add Red (decode xs)

decode (O:I:xs) = add Blue (decode xs)

decode (I:O:xs) = add Yellow (decode xs)

decode _ = Nothing

add :: Color -> Maybe [Color] -> Maybe [Color]

add color xs =

? case xs of

? ? Nothing -> Nothing

? ? Just ys -> Just (color:ys)

這種方案更容易理解。我們需要一個輔助函數(shù)add,來把Color 和 Just [Color] 類型組成list,像“:” operator一樣。 由于此時是Maybe Type,我們無法應(yīng)用“:”operator,為此構(gòu)建了add。剩余的則為基本迭代,decode一對然后再一對,每次的結(jié)果都返回成list。






最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容