Functional Programming (7)-Data structure-list-folding algorithm

Source: Internet
Author: User

The folding algorithm is a typical algorithm of list. Many functions can be combined (function composition) by folding algorithm. So the folding algorithm is also the basic component in functional programming (function Combinator). Understanding the principles of the folding algorithm is crucial to understanding the functional composition. The folding algorithm can be folded right and left folded. Let's start with the right folding (foldright):

The right folding algorithm for list (A,B,C) can be obtained from the above two illustrations: OP (A,op (B,op (c,z)), which shows that the parentheses start from the right. Calculation Method Two: OP (a,sub), sub is a repeating subtree, can be sure to use recursive algorithm. Here Z represents a starting value. We can now deduce the Foldright function signature:

1       def Foldright[a,b] (L:list[a], Z:b) (OP: (b) = b): b = l Match {2case            Nil =  Z3case            Cons (h,t) = op (h,foldright (T,z) (f))4       }

Note that foldright is not a tail recursive algorithm (tail recursive). We try to operate on a list (three-to-one), adding first:

1 foldright (List, 0) ((x, y) = x + y)          //> res13:int = 62 foldright ( List (0) {_ + _}                   //> res14:int = 6

We can use the "equal substitution" method to simplify:

1 foldright (list, 1) {_ * _}                   //> res16:int = 62 foldright (list) , Nil:list[int]) {(b) = Cons (a+10, b)}3                                                   //> Res17:ch3.list.list[int] = Cons (11,cons (12,cons (13,nil)))

Note the above starting value of 1 and Nil:list[int]. The type of z may not be a, so the result of OP may not be a type, but in the above examples of addition and multiplication z is of type int. However, in the list refactoring example Z is list[int] type, so the OP result is also list[int] type, this should pay special attention to.

Let's take a look at the left folding algorithm:

From the analysis, the left folding algorithm is the operation op of all list elements to Z. As can be seen from Figure two, op operation for op after Z,a operation is performed as Z and b again, so it loops. It appears to be a recursive algorithm, and z is a value that accumulates with OP: Op (Op (z,a), b), C). The parentheses of the left folding algorithm start from the left. Take a look at the implementation of Foldleft:

1       def Foldleft[a,b] (L:list[a], Acc:b) (OP: (b,a) = b): b = l Match {2case            Nil =  ACC3case            Cons (h,t) = Foldleft (t,op (Acc,h)) (OP)4       }

Note that Z (zero) becomes ACC (accumulator), OP: (b,a) = B, and Foldright's OP function entry order is reversed. Foldleft is a tail-recursive method.

1Foldleft (List, 0) ((b,a) = a + b)//> res18:int = 62Foldleft (List, 0) {_ + _}//> res19:int = 63Foldleft (List, 1) ((b,a) = A * b)//> res20:int = 64Foldleft (List, 1) {_ * _}//> res21:int = 65Foldleft (List (i), Nil:list[int]) {(b,a) = Cons (a+10, b)}6                                                   //> Res22:ch3.list.list[int] = Cons (13,cons (12,cons (11,nil)))

The cumulative value of the above addition and multiplication acc is a type, but note that the list refactoring ACC is list[int] type, at this time the position of the OP into the parameter is very important. Notice again that the element arrangement of the Foldleft refactoring list is the reverse Cons (13,cons (12,cons (11,nil)). We can still use the "equal substitution" method for simplicity:

1 //(List (x1,x2,x3...x{n-1}, xn) foldleft acc) op = = (... (ACC op x1) op x2) ...) Op x{n-1}) op xn2  //Foldleft (Cons (1,cons (2,cons (3,nil)), 0) {_ + _}3  //Foldleft (Cons (2,cons (3,nil)), (0 + 1)) {_ + _}4  //Foldleft (Cons (3,nil), ((0 + 1) + 2)) {_ + _}5  //Foldleft (Nil, (((0 + 1) + 2) + 3)) {_ + _}6  //(((0 + 1) + 2) + 3) + 0 = 6

In addition to Foldright,foldleft, the folding algorithm also includes: Reduceright,reduceleft,scanright,scanleft.

Reduceleft is the first, Reduceright is a folding algorithm with the last list element as the starting value, with no separate starting value:

1def Reduceleft[a] (L:list[a]) (OP: (a,a) = a): A =L Match {2            CaseNil = Sys.error ("Empty list!")3            CaseCons (h,t) =Foldleft (T,h) (OP)4       }5def Reduceright[a] (L:list[a]) (OP: (a,a) = a): A =L Match {6            CaseCons (H,nil) =h7            CaseCons (h,t) =op (H,reduceright (T) (OP))8}
1  Reduceleft (list (+)) {_ + _}                  //> res23:int = 62  reduceright (list (+)) {_ + _}                 //> res24:int = 6

Scanleft, scanright Each op result into a newly generated list as the result of the return.

Implement Scanleft First:

1        def Scanleft[a] (l:list[a],z:a) (OP: (a,a) = A): list[a] = l Match {2case             Nil =>
   
     Cons (z,nil)
    3case            
     Cons (h,t) =
     Cons (z,scanleft (T,op (Z,h)) (OP))
    4         }
   
1 scanleft (List 0) {_ + _}                   //> Res25:ch3.list.list[int] = Cons (0,cons (1, Cons (3,cons (6,nil) )))

Try simplicity:

1  //(List (x1,x2,x3...x{n-1}, xn) scanleft acc) op = = (... (ACC op x1) op x2) ...) Op x{n-1}) op xn2  //Scanleft (Cons (1,cons (2,cons (3,nil)), 0) {_ + _}3  //Cons (0,scanleft (Cons (1,cons (2,cons)), 0) {_ + _})4  //Cons (0,cons ((0 + 1), Scanleft (Cons (2,cons (3,nil)), (0 + 1)) {_ + _} )5  //==> Cons (0,cons (1,scanleft (Cons (2,cons), 1) {_ + _}))6  //Cons (0,cons (1,cons (2 + 1,scanleft (Cons (3,nil), 1 + 2) {_ + _} )))7  //==> Cons (0,cons (1,cons (3,scanleft (Cons), 3) {_ + _} )))8  //Cons (0,cons (1,cons (3,cons (3 + 3,foldleft (Nil, 3 + 3) {_ + _} )))9  //==> Cons (0,cons (1,cons (3,cons (Nil, 6) {_ + _} )))Ten  //Cons (0,cons (1,cons (3,cons (6,nil) ))

Re-implementation of Scanright:

1def Reverse[a] (L:list[a]): list[a] = Foldleft (L,nil:list[a]) {(acc,h) = =Cons (H,ACC)}2        3def Scanright[a] (l:list[a],z:a) (OP: (a,a) = A): list[a] =  {4var scanned =List (z)5var acc =Z6var ll =reverse (L)7var x =Z8                  while (9 ll Match {Ten                          CaseNil =false One                          CaseCons (h,t) = {x = h; ll = t;true } A                     } -                 ) { -ACC =op (acc,x) thescanned =Cons (acc,scanned) -                 } - scanned -}

It is not possible to think of a recursive algorithm to implement the Scanright method, only with the while loop to solve. Note that although temporary variables are used, these variables are locally closed, so scanright is still a pure function. The Scanright element Traversal (Traverse) order is reversed, so the list (all-in-one) is first changed to list (3,2,1) with the reverse function.

1 scanright (0) {_ + _}                  //> Res26:ch3.list.list[int] = Cons (6,cons (5,cons (3, Cons (0,nil) )))

Note that the results of scanright and scanleft differ. This is because the algorithm is different: the element traversal (Traverse) order is different.

The following is a demonstration of the folding algorithm as a basic component (Combinator) to implement some function functions:

function + + was implemented last time, i.e. append. We can also use foldleft and foldright to achieve:

1       def Appendbyfoldright[a] (L1:list[a], L2:list[a]): list[a] = Foldright (L1,L2) {(H,ACC) = Cons (H,ACC)}2        def Appendbyfoldleft[a] (L1:list[a], L2:list[a]): list[a] = foldleft (reverse (L1), L2) {(acc,h) = Cons (H, ACC)}
1 appendbyfoldleft (list), List (3,4))             //> Res27:ch3.list.list[int] = Cons (1,cons (2, Cons (3,cons (4,nil)))2 appendbyfoldright (list), List (3,4))            //> RES28: Ch3.list.list[int] = Cons (1,cons (2,cons (3,cons) ))

Since the function of append is to splice two lists together, the final result must be guaranteed in the order of the list elements. So the reverse was used in the appendbyfoldleft. Note again that the foldleft and Foldright are opposite in the OP parameter position.

Some of the functions implemented by the previous recursive algorithm can be implemented using a folding algorithm:

1       def Map_1[a,b] (L:list[a]) (f:a = B): list[b] = Foldright (L,nil:list[b]) {(H,ACC) = Cons (f (h), ACC)}
1       if Else ACC} 2       def Flatmap_1[a,b] (L:list[a]) (f:a = List[b]): list[b] = Foldright (L,nil:list[b]) {(H,ACC) = Appendbyfoldright (f (h), ACC)}
1       def Lengthbyfoldright[a] (L:list[a]): Int = Foldright (l,0) {(_,ACC) = ACC + 1 }2       def lengthbyfol Dleft[a] (L:list[a]): Int = Foldleft (l,0) {(acc,_) + ACC + 1}


There are some more indirect:

1     def Concat[a] (Ll:list[list[a]): list[a] = foldright (Ll,nil:list[a]) {appendbyfoldright}2  

This function can be used to implement FLATMAP:

1      def Flatmap_1[a,b] (L:list[a]) (f:a = List[b]): list[b] = conCat (Map (L) (f))

If you understand that the above functions are difficult to implement, you can start with the type matching, or try to use the "equal substitution" method of simple tracking.

Functional Programming (7)-Data structure-list-folding algorithm

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.