簡體   English   中英

理解函數中的Haskell遞歸

[英]Understanding Haskell recursion in functions

我一直在為Haskell使用一些資源:了解一下Haskell和wikibook。 但是,我很難找到一個解釋,幫助我理解遞歸。 我附上了一本代碼來自'Learn you a Haskell'一書,我對此有所了解。

maximum' :: (Ord a) => [a] -> a  
maximum' [] = error "maximum of empty list"  
maximum' [x] = x  
maximum' (x:xs)   
    | x > maxTail = x  
    | otherwise = maxTail  
    where maxTail = maximum' xs

我理解上面的所有代碼,直到最后一行'maxTail = maximum'xs'。 我不明白的是,如何通過調用最大值來評估代碼以返回最大值。 或者它如何知道最大'是列表中的最高元素。

另一個例子:

reverse' :: [a] -> [a]  
reverse' [] = []  
reverse' (x:xs) = reverse' xs ++ [x]

了解所有內容,直到在列表的尾部調用reverse'。 換句話說,它如何知道反向'意味着反轉尾部元素。

我真的很感激解釋,並且如果它很簡單就道歉,我是這種語言的新手。

逐行排列,所以你希望更好地理解它:

1| maximum' :: (Ord a) => [a] -> a  
2| maximum' [] = error "maximum of empty list"  
3| maximum' [x] = x  
4| maximum' (x:xs)   
    | x > maxTail = x  
    | otherwise = maxTail  
    where maxTail = maximum' xs

在第1行:你說你得到一個列表並返回該類型的一個元素。 此外,該列表中的元素必須是可以包含的,因此您可以將它們放入訂單中。

在第2行:你有一個邊緣情況,你說如果你得到一個空列表作為輸入,那個空列表中不能有“最高值”,所以你結束該函數有一個錯誤。

在第3行:你有另一個邊緣情況,你說如果你得到一個包含1個元素的列表,那個元素必須是最高元素,所以你返回它。

在第4行:您使用模式匹配來匹配第一個元素( x )和列表的其余部分( xs )。 然后檢查x是否大於maxTail ,其中maxTail函數調用的結果maximum'與列表xs的其余部分相同。

如果x大於maxTail則返回x ,否則maxTail大於x並返回maxTail


我認為有一些數字的例子也應該有幫助:

輸入:

[2, 5, 4, 13]

呼叫:

maximum' [2, 5, 4, 13]

怎么了:

maximum' (x  :  xs)
          ↓     ↓
maximum' (2:[5, 4, 13]) 
           │
           ↓                               result 13
     x > maxTail = x                         ↑
     2 > maximum' [5, 4, 13] = x  //2 > 13 = 13 ← ────┐
         │                                            │
         └  maximum' (x :  xs)                        │
                      ↓    ↓                          │
            maximum' (5:[4, 13])                      │
                       │                              │
                       ↓                              ↑
                 x > maxTail = x                      │
                 5 > maximum' [4, 13] = x  //5 > 13 = 13 ← ─────┐
                     │                                          │
                     └  maximum' (x: xs)                        │
                                  ↓  ↓                          │
                        maximum' (4:[13])                       │
                                   │                            │
                                   ↓                            ↑
                              x > maxTail = x                   │
                              4 > maximum' [13] = x  //4 > 13 = 13  ┐
                                  │                                 │
                                  └ maximum' [x] = x                ↑
                                    maximum' [13] = 13 → ───────────┘

在你的第二個例子中它幾乎是一樣的:

1| reverse' :: [a] -> [a]  
2| reverse' [] = []  
3| reverse' (x:xs) = reverse' xs ++ [x]

在第1行:你說你得到一個列表並返回一個列表。

在第2行:你有一個邊緣情況,你說如果你得到一個空列表,反向列表也只是空的。

在第3行:您再次使用模式匹配來匹配列表的第一個元素( x )和它的尾部( xs )。

現在你只需使用++將兩個列表附加在一起,這是列表中反向尾部的第一個元素。


我希望再舉一個例子,它會更清楚一些:

輸入:

[1, 2, 3]

呼叫:

reverse' [1, 2, 3]

怎么了:

reverse' (x : xs)
          ↓   ↓
reverse' (1:[2, 3])
           │                               result [3, 2, 1]
           ↓                                       ↑
   (reverse' [2, 3]) ++ [1]  //[3, 2] ++ [1] = [3, 2, 1] ← ────┐
    │                                                          │
    └ reverse' (x: xs)                                         │
                ↓  ↓                                           │
      reverse' (2:[3])                                         │
                 │                                             ↑
                 ↓                                             │
         (reverse' [3]) ++ [2]  //[3] ++ [2] = [3, 2] ← ───┐ → ┘
          │                                                │
          └ reverse' (x:xs)                                │
                      ↓ ↓                                  │
            reverse' (3:[])                                │
                       │                                   ↑
                       ↓                                   │
               (reverse' []) ++ [3]  //[] ++ [3] = [3] ┐ → ┘
                │                                      ↑           
                └ reverse' [] = [] → ──────────────────┘

長度

length' [] = 0

情況1:空列表的長度為0。

length' (x:xs) = 1 + length' xs

情況2:具有至少一個元素的列表的長度比列表尾部的長度多1,我們通過重復案例2找到,直到不再有元素,滿足情況1。

length' [1, 2, 3]
=
length' (1 : (2 : (3 : [])))
=
1 + length' (2 : (3 : []))
=
1 + (1 + length' (3 : []))
=
1 + (1 + (1 + length' []))
=
1 + (1 + (1 + 0))
=
1 + (1 + 1)
=
1 + 2
=
3

相反

reverse' [] = []  

情況1:如果列表為空,則其反向也是空列表。

reverse' (x:xs) = reverse' xs ++ [x]

情況2:如果列表至少有一個元素,那么我們可以拉出第一個元素,將其移動到最后,並以相同的方式反轉其余元素 - 通過使用案例2繼續列表直到沒有元素保留,滿足情況1。

reverse' [1, 2, 3]
=
reverse' (1 : (2 : (3 : [])))
=
reverse' (2 : (3 : [])) ++ [1]
=
reverse' (3 : []) ++ [2] ++ [1]
=
reverse' [] ++ [3] ++ [2] ++ [1]
=
[] ++ [3] ++ [2] ++ [1]
=
[3, 2, 1]

最大值

maximum' [x] = x  

情況1:如果列表只有一個元素,那么該元素是最大值。

maximum' (x:xs)   

案例2:如果一個列表至少有一個元素,那么......

    | x > maxTail = x  

......第一個比所有其他都大,在這種情況下它是最大的; 要么…

    | otherwise = maxTail  

......不是,所以最大值是所有其他人中最大的......

    where maxTail = maximum' xs

...我們通過在案例2的列表中繼續查找,直到只剩下一個元素,滿足案例1。

我將重新定義maximum'的定義,以便更容易地顯示它如何替代:

maximum' (x:xs) = let maxTail = maximum' xs in
    if x > maxTail then x else maxTail

現在:

maximum' [1, 3, 2]
=
maximum' (1 : (3 : (2 : [])))
=
let maxTail1 = maximum' (3 : (2 : [])) in
    if 1 > maxTail1 then 1 else maxTail1
=
let maxTail1 =
    (let maxTail2 = maximum' (2 : []) in
        if 3 > maxTail2 then 3 else maxTail2) in
    if 1 > maxTail1 then 1 else maxTail1
=
let maxTail1 =
    (let maxTail2 = 2 in
        if 3 > maxTail2 then 3 else maxTail2) in
    if 1 > maxTail1 then 1 else maxTail1
=
let maxTail1 = (if 3 > 2 then 3 else 2) in
    if 1 > maxTail1 then 1 else maxTail1
=
let maxTail1 = 3 in
    if 1 > maxTail1 then 1 else maxTail1
=
if 1 > 3 then 1 else 3
=
3

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM