Functional Programming (23)-generic function according to type-monad

Source: Internet
Author: User

To put it simply: Monad is the most generalized data model (high-order data type) in functional programming. It covers not only the functional behavior and operation of all underlying types (primitive types), but also any high-order class or custom class that, once they have monad characteristics, can provide a common set of functional programming in functional programming as any type of Monad instance. So some people regard functional programming as monadic programming is not too. So, what exactly is Monad?

Before we discussed monoid, we have said that it is a special category, and monoid instances of all data types collectively have a set of monoid specific operations and follow a set of monoid behavior laws. In this way, we can think of monoid as an abstract data model, and the use of special monoid instances in functional algorithms can achieve the desired effect without the need to modify the algorithm. Then it can be said that Monad is a more general, more abstract, more extensive coverage of higher-order data types than monoid.

In fact, when designing a functional library component (Combinator), we try to avoid repetitive coding by extracting common or common operations to form some new high-order types (higher types), which is the new abstract type (abstraction). This allows us to use these common types in different component libraries for similar operations. Let's take a look at one of the following abstract processes:

We discussed some of the data types earlier. They all have a common function: Map

1   def Map[a,b] (La:list[a]) (f:a = b): List[b]2   def Map[a,b] (Oa:option[a]) (f:a = b): Opt ION[B]3   def Map[a,b] (Pa:par[a]) (f:a = B): par[b]4   def Map[a,b] (sa: State[s,a]) (f:a = B): state[s,b]

These functions all have highly similar variants (signature), unlike the specific data types they are applied to. Then we should be able to abstract this map: by adding a higher-order type functor, it is used to generalize the map:

1   trait Functor[f[_]] {2       def Map[a,b] (A:f[a]) (f:a = B): f[b]3   }

Note that the application types in the map example above are high-order types; List[a], Option[a], Par[a] ... are f[a] this form. So Functor's class parameters are f[_], ie: functor[list], functor[option], Functor[par] ..., in which f[_] is f[a],a can be any type. We can design a list of functor instances:

1   extends Functor[list] {2       def Map[a,b] (La:list[a]) (f:a = B): list[b] = la map f3< /c18>   }

Change F to list. Other types of functor instances:

1  extends Functor[option] {2       def Map[a,b] (Oa:option[a]) (f:a = B): option[b] = oa map f3  }4   extends  Functor[stream] {5       def Map[a, b] (Sa:stream[a]) (f:a = b): stream[b] = sa map f6   }

We only need to use the corresponding functor instance for different types of operations:

1 listfunctor.map (list (+)) {_ + ten}             //> Res0:list[int] = List (one,one,2)   Optionfunctor.map (Some (1)) {_ + ten}               //> Res1:option[int] = Some (one)

The operating modes are identical. But to be honest, the examples above are meaningless, because the specific type of application natively supports map. In other words, list,option is functor itself. In other words: they can all map, so they are functor. See below how to use the functor bar:

1   trait Functor[f[_]] {2       def Map[a,b] (A:f[a]) (f:a = B): f[b]3       def Unzip[a,b] (fab:f[(A, B)]): (f[a],f[b]) = {4         (map (fab) {a = A._1},map (fab) {a = = a._ 2})5      }6   }

In this example, I specifically put the whole trait declaration in. The map here is still abstract, meaning that it also needs to be implemented in a specific type instance. We were designing the unzip for F. In trait functor we can be sure that f[(A, A, b)] supports map, so we can complete the implementation of the unzip function. This is the function of abstraction. When we use unzip, just make sure the incoming parameter fab is functor. This allows the unzip to support all packages (A, b) of the functor:

1 listfunctor.unzip (List (1,10), (2,20), (3,30))    //> Res0: (List[int], list[int]) = ( List (1, 2, 3), List (ten,())2  optionfunctor.unzip (Some ()))                 //> Res1: ( Option[int], option[int]) = (Some (1), Some (2))

What does this functor have to do with Monad? But what kind of abstract purpose and pattern might be associated with Monad? So again, the deduction: In the previous data type design we had to encounter a lot of MAP2 functions:

1def Map2[a,b,c] (La:list[a], lb:list[b]) (f: (A, B) + C): list[c] = {2La FlatMap {a = lb map {b =F (A, B)}}3   }4def Map2[a,b,c] (Oa:option[a], ob:option[b]) (f: (A, B) + C): option[c] = {5OA flatmap{a = ob map {b =F (A, B)}}6   }7def Map2[a,b,c] (Pa:par[a], pb:par[b]) (f: (A, B) + C): par[c] = {8PA flatmap{a = PB Map {b =F (A, B)}}9}

Look at these MAP2 functions: not only the same style, but also the same implementation method. Different types of data are also specific to the application of the receptor. It seems that we have repeatedly written the MAP2 component because of the different data types. We should find a way to implement MAP2 once, so that all data type instances can be used to completely avoid repeated coding. To be sure, these methods must be related to the generality of abstraction.

In the previous chapters we have been designing the most basic operational functions or components for the characteristics of certain data types. Because of the different data types we have repeatedly written the MAP2 component. Now we see that MAP2 can be implemented using FLATMAP and maps. So flatmap and map are the most basic and most common components? In fact, map can be implemented with FLATMAP and unit:

1   def Map[a,b] (Pa:par[a]) (f:a = B): par[b] = {2       FlatMap (PA) {A = unit (f (A))}  3   }

Then we will first select Unit + Flatmap as the most basic component. Of course, from the preceding deduction we can conclude that the unit + FLATMAP basic component is more abstract (more generalized) than functor, because the map can be implemented with unit + FLATMAP. We call this abstract model Monad, which inherits the characteristics of functor, which is functor because Monad can map. We can first use trait to express Monad:

1Trait Monad[m[_]]extendsFunctor[m] {2 def Unit[a] (A:A): M[a]3def Flatmap[a,b] (Ma:m[a]) (f:a =m[b]): M[b]4def Map[a,b] (Ma:m[a]) (f:a = B): m[b] = {5FlatMap (MA) {a =Unit (f (A))}6       }7def Map2[a,b,c] (Ma:m[a], mb:m[b]) (f: (A, B) + C): m[c] = {8FlatMap (MA) {A + = map (MB) {b = =F (A, B)}}9       }Ten}

In this trait the unit and the Flatmap are abstract. This means that the Monad instances of each type must implement unit and Flatmap, and automatically acquire the map and MAP2 two components.

1Val Listmonad =NewMonad[list] {2def Unit[a] (a:a) =List (a)3def Flatmap[a,b] (La:list[a]) (f:a = List[b]): list[b] = {4 la FlatMap F5      }6}//> Listmonad:ch11.monad.monad[list] = [email protected]7                                                   //| 0C128   9Listmonad.map (List (+)) {_ + 10}//> Res0:list[int] = List (one, one, one)TenLISTMONAD.MAP2 (list, list (3,4)) {(A, b) =List (A, b)} One                                                   //> Res1:list[list[int] = list (list (1, 3), List (1, 4), List (2, 3), List (2, 4)) A                                                   //| 

Indeed, we have automatically obtained the available maps and MAP2 from the Listmonad.

The Optionmonad is this:

1Val Optionmonad =NewMonad[option] {2def Unit[a] (a:a) =Some (a)3def Flatmap[a,b] (Oa:option[a]) (f:a = Option[b]): option[b] = {4 OA FlatMap F5       }6}//> Optionmonad:ch11.monad.monad[option]{def unit[a] (A:A): some[a]} = ch11.m7                                                   //| [Email protected]8Optionmonad.map (Some (1)) {a = a + 10}//> Res2:option[int] = Some (one)9OPTIONMONAD.MAP2 (Some (1), Some (2)) {_ + _}//> Res3:option[int] = Some (3)

Now it seems that we can say that any data type that can be flatmap (with Flatmap function) is monad.

We can enrich the current Monad component library, add more common components, so that the Monad abstract model can be more practical:

1Trait Monad[m[_]]extendsFunctor[m] {2 def Unit[a] (A:A): M[a]3def Flatmap[a,b] (Ma:m[a]) (f:a =m[b]): M[b]4def Map[a,b] (Ma:m[a]) (f:a = B): m[b] = {5FlatMap (MA) {a =Unit (f (A))}6       }7def Map2[a,b,c] (Ma:m[a], mb:m[b]) (f: (A, B) + C): m[c] = {8FlatMap (MA) {A + = map (MB) {b = =F (A, B)}}9       }Tendef Sequence[a] (Lm:list[m[a]): m[list[a]] = { OneLm.foldright (Unit (Nil:list[a)) {(b) =Map2 (A, B) {_:: _}} A       } -def Travers[a,b] (La:list[a]) (f:a = M[b]): m[list[b]] = { -La.foldright (Unit (NIL:LIST[B)) {(b) =Map2 (f (a), b) {_:: _}} the       } -def Replicatem[a] (N:int, Ma:m[a]): m[list[a]] = { -           if(n = = 0) unit (Nil) -           ElseMAP2 (Ma,replicatem (n-1, MA)) {_ :: _} +       } -def Factor[a,b] (Ma:m[a], mb:m[b]): m[(A, b)] = { +MAP2 (MA,MB) {(b) =(A, b)} A       } atdef Cofactor[a,b] (E:either[m[a],m[b]): m[either[a,b]] = { - e Match { -                CaseRight (b) = map (b) {x =Right (x)} -                CaseLeft (a) = Map (a) {x =Left (x)} -           } -       } in}

As you can see, our newly added components are implemented in the two basic components of Unit + FLATMAP, which are higher-order components. So is it possible to say monadic programming is FLATMAP programming?

Functional Programming (23)-generic function according to type-monad

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.