Scalaz (21)-type illustration: Liskov and Leibniz-type evidence

Source: Internet
Author: User

Leskov,leibniz, awkward name, what kind of work? It happened that something was found in the Scalaz source code: Scalaz/bindsyntax.scala

/** Wraps a value ' self ' and provides methods related to ' Bind '*/FinalclassBindops[f[_],a]Private[Syntax] (Val Self:f[a]) (ImplicitVal f:bind[f]) extends Ops[f[a]] {////Import liskov.<~<, leibniz.===def Flatmap[b] (f:a= = F[b]) =F.bind (self) (F) def&GT;&GT;=[B] (f:a = f[b]) =F.bind (self) (F) def∗[b] (f:a= = F[b]) =F.bind (self) (F) def Join[b] (ImplicitEv:a <~< f[b]): f[b] =F.bind (self) (EV (_)) Defμ[b] (ImplicitEv:a <~< f[b]): f[b] =F.bind (self) (EV (_)) def>>[b] (B: = = F[b]): f[b] = F.bind (self) (_ =b) def Ifm[b] (iftrue:= = F[b], Iffalse: + f[b]) (ImplicitEv:a = = = Boolean): f[b] ={val Value:f[boolean]=Ev.subst (self) F.IFM (value, Iftrue, Iffalse)}////}

The original Liskov and Leibniz are both the type class of the Scalaz library. Leskov <~< and Leibniz = = = are all type manipulation symbols, actually scalaz own version of the type restriction operator <:< and =:=. found that these two functions look particularly strange to get a thorough understanding of Leskov and Leibeniz's ideas:

def Join[b] (implicit ev:a <~< f[b]): f[b] == = F[b], iffalse: = = F[b]) (implicit EV: A = = Boolean): f[b] =    {= ev.subst (self)    F.IFM (value, Iftrue, Iffalse)  }

The implicit parameters of the two functions use <~< and = = = respectively. Since it corresponds to the <:< and =:= of the standard Scala library, we can first look at the use of <:< and =:=:

A =:= B means that a must be of type B, such as: a =:= int means a must be of type Int. A <:< B means that a must be a subclass of B, or that we can substitute a for B at any time. So now that you know the type of a, why do you need to frame it again? In fact, in some cases it is necessary to further frame the type A, and take a look at the following example:

 Case classFoo[a] (a:a) {//Type A can be of any typedef getlength (ImplicitEv:a =:= String): Int = A.length//a must be a stringDef getsquare (Implicitev:a <:< int): int = A * a//a must be an int or subclass}foo ("Word length"). GetLength//> res0:int = OneFoo (3). Getsquare//> res1:int = 9Foo ("Word length"). Getsquare//cannot prove that String <:< IntFoo (3). GetLength//cannot prove that Int =:= String

The type parameter of Class Foo[a] can be any type, meaning that we can instantiate Foo with any type. Then we use the implicit EV in class to define the type of a a step closer. This way we can correctly use the GetLength and Getsquare functions, or a compilation error occurs. This example is basically able to explain the =:=,<:< clearly.

So since Scalaz's <~< and = = = <:< and =:=, let's try the Scalaz version in the example above:

1 Package Exercises2 Import Scalaz._3 Import Scalaz._4Import liskov.<~<, leibniz.===5 ObjectEvidence {6  Case classFoo[a] (a:a) {//Type A can be of any type7def getlength (ImplicitEv:a = = = String): Int = EV (A). length//a must be a string8Def getsquare (Implicitev:a <~< int): int = EV (a) * EV (a)//a must be an int or subclass9 }TenFoo ("Word length"). GetLength//> res0:int = One OneFoo (3). Getsquare//> res1:int = 9 AFoo ("Word length"). Getsquare//could not find implicit value for parameter Ev:scalaz. Liskov.<~<[string,int] -Foo (3). GetLength//could not find implicit value for parameter Ev:scalaz. Leibniz.===[int,string]

We see that we can get the same effect.
Then look at the principle, use the Scalaz version of the research object. Because Liskov and Leibniz are both the type class of Scalaz, we are going to parse implicit conversions for implicit arguments. First look at some definitions of Leibniz: Scalaz/leibniz.scala

Sealed Abstract class  Leibniz[-l, +h;: L, A;: l <: H, B;: L <: h] {  = Subst[id] (a)  ;: L <: H]] (P:f[a]): f[b] ...

First of all, ignore these types of parameter qualification, very chaotic, in short, around is a and B in a type of area. It is worth noting that apply, and subst this abstract function: input parameter f[a] return result f[b]. because a = = = String is actually an expression of leibniz[a,string], we need to parse the Leibniz instance. This was found within Leibniz.scala:

ObjectLeibniz extends leibnizinstances with leibnizfunctions{/** ' (a = = B) ' is a supertype of ' leibniz[l,h,a,b] '*/type===[A,B] =leibniz[⊥,?, A, B]} and trait leibnizfunctions {import Leibniz._/** Equality is reflexive--we rely on subtyping to expand this type*/  Implicitdef Refl[a]: Leibniz[a, A, a, a] =NewLeibniz[a, A, a, a] {def subst[f[_: a <: a]] (P:f[a]): f[a] =P}/** We can witness equality by using it to convert between types * We rely on subtyping Leibniz Arrow*/  Implicitdef Witness[a, b] (f:a = = = b): A = = b =f.subst[({typeλ[x]= A =X}) #λ] (Identity)Implicitdef Subst[a, B] (A:A) (ImplicitF:a = = = B): b =F.subst[id] (a) ...

When we try to find the leibniz[a,string] instance, the only thing that can possibly be leibniz[a,a,a,a] is that the type conversion is actually done by turning the subst parameter into a return result. We can use the following method to prove that:

Implicitly[int = = = Int]     //> Res2:scalaz. Leibniz.===[int,int] = [email protected]implicitly[string = = = Int]  //could not find implicit Value for parameter E:scalaz. Leibniz.===[string,int]

EV (a) is apply (a) =subst[id] (a) =a, secretly subst help type conversion a=>string, which we can re-prove by swapping the position of a and String:

  def getlength (implicit ev:string = = = A): Int = EV (a). Length  //type mismatch;  Found   : A  required:string

The same we can see Liskov definition: Scalaz/liskov.scala

Sealed Abstract class Liskov[-a, +B] {  = liskov.witness (this) (A)  def subst[f[-_]] (P:f[b]): F[a] ... 

The same is the SUBST function: First f[-_] is contravariant, F[b]=>f[a] requires a is a subclass of B. Implicit conversion parsing:

ObjectLiskov extends liskovinstances with liskovfunctions {/**a Convenient type alias for Liskov*/type<~<[-a, +b] =liskov[a, B]/**a flipped alias, for those used to their arrows running*/type>~>[+b,-A] =liskov[a, B]} and trait liskovfunctions {import Liskov._/**lift Scala ' s subtyping relationship*/  Implicitdef Isa[a, B;: A]: a <~< B =New(A <~<B) {def subst[f[-_]] (P:f[b]): f[a] =P}/**we can witness equality by using it to convert between types*/  Implicitdef Witness[a, b] (lt:a <~< b): A = + b ={type f[-X] = X = =B Lt.subst[f] (identity)}/**subtyping is reflexive*/  Implicitdef Refl[a]: (a <~< a) =New(A <~<A) {def subst[f[-_]] (P:f[a]): f[a] =p} ...

We can see that the input parameter in the type conversion function subst of the A <~< B instance f[b] is directly substituted for the return result F[a], because f[] is the inverse (contravariant) and A is a subclass of B. That is, we can use a instead of B.

OK, let's try to analyze the join function mentioned above. As we all know, the Join function is a monad (Flaten function). This version can be found here: Scalaz/bind.scala

  /* * Sequence the inner ' f ' of ' FFA ' after the outer ' f ', forming a    */    = Bind (FFA) (A + a)

This is easy to understand. But now we're dealing with this version: Scalaz/bindsyntax.scala

def Join[b] (implicit ev:a <~< f[b]): f[b] = F.bind (self) (EV (_))

Using Leskov here, let's see what happened:

List (list (1), List (2), List (3)). Join       //> Res3:list[int] = List (1, 2, 3 )List (1. Some,2. Some,3. some). Join          //could not find Implicit value for parameter Ev:scalaz. LISKOV.<~<[OPTION[INT],LIST[B]]

The correct EV instance requires Liskov[list[list[int]],list[int]],list[list[int]] is a subclass of List[int]. The input parameter f[b] in the SUBST function directly replaces the return result F[a]. So:

F.bind (List[list[a]) (EV (LIST[A]))

=f.bind (List[list[a]]) (Witness (Leskov[list[list[int]],list[int]) (List[list[int]])

=f.bind (List[list[a]) (List[int])

=list[int]

We see List[list[int]] [converted to list[int] by witness.

The above analysis seems magical, but we can vaguely feel the powerful inference capabilities of the Scala type system. By providing some types of instances, it generates a lot of source code for us.

Scalaz (21)-type illustration: Liskov and Leibniz-type evidence

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.