In the previous discussion, we mentioned that the free data structure is the most simplified structure that produces some type, such as: monoid, Monad, and so on. We also proved that list[a] is a free monoid. Let's look at the definition of free monad structure free: Scalaz/free.scala
/** A free operational monad for some functor ' S '. The Binding is-done using the heap instead of the stack, * allowing Tail-call elimination. */Sealed Abstract classFree[s[_], A] {.../** Return from the computation with the given value.*/ Private[Scalaz] Case classReturn[s[_], a] (A:A) extends Free[s, a]/** Suspend The computation with the given suspension.*/ Private[Scalaz] Case classSuspend[s[_], a] (A:s[free[s, a]]) extends Free[s, a] ...
We have shown in the previous article that free is free monad, because free is a monad and its structure is the simplest:
1, Free[s[_],a] can represent an operation
2, Case class return is a data structure. Return (A:A) represents the end of the operation, and result A is stored in the structure. Another meaning is Monad.point (A:A), which upgrades an arbitrary a-value A to free
3, Case class suspend is another data structure. Suspend (A:s[free[s,a]]) represents the storage of the next operation in the structure. If using Monad.join (A:f[f[a]), then the inside F[a] should be a free[s,a], so that we may put the end of the operation Structure Return[s,a] (A:A) into the suspend to represent the next end of the operation.
Note that Suspend (A:s[free[s,a]) is a recursive type, S must be a functor, but not any functor, but the free[s,a of map over functor], which is the operation of another free[s,a] value. If this free is return, the result of the operation is returned, and if it is suspend, the recursive operation continues.
In a nutshell, free is a generator that upgrades functor S[_] to Monad. We can use the FREE.LIFTF function to upgrade any functor to Monad. Look at the FREE.LIFTF's function style and you'll find out:
/** /= S[a]) (implicit s:functor[s]): Free[s, A] = Suspend ( S.map (value) (Return[s, A]))
LIFTF can upgrade a s[a] to free[s,a]. We use an example to prove that:
1 Package Exercises2 Import Scalaz._3 Import Scalaz._4 Import Scala.language.higherKinds5 Import Scala.language.implicitConversions6 ObjectFreelift {7Trait config[+A] {8DefGet: A9 }Ten ObjectConfig { Onedef Apply[a] (A:A): config[a] =NewConfig[a] {defGet=A} A ImplicitVal Configfunctor =NewFunctor[config] { -def Map[a,b] (Ca:config[a]) (f:a = B) = Config[b] (f (ca.Get)) - } the } - -Val freeconfig = FREE.LIFTF (Config ("Hi config"))//> Freeconfig:scalaz. Free[exercises.freelift.config,string] = Suspend ([email protected])
In the above example, Config is a functor of the operation a value. We can use FREE.LIFTF to upgrade Config (String) to free[config,string]. In fact, we can eliminate this must be the threshold of functor, because with Coyoneda can be any f[a] disassembled into coyoneda[f,a], and Coyoneda is born a functor. Let's look at a f[a that can't implement the map function]:
1 trait Interact[+a] // 2 // println (prompt:string) then ReadLine returns String 3 case class Ask (prompt:string) extends interact[string] 4 // println (msg:string) does not reverse any value 5 case class Tell (msg:string) extends Interact[unit]
Since ask and tell do not return a generic value, it is not necessary or impossible to implement the map function, Interact[a] is a high-order class that is not functor. We have to turn it into a coyoneda provided to free to generate Monad:
1 free.liftfc (Tell ("hello")) //> Res0:scalaz. Free.freec[exercises.freelift.interact,unit] = Suspend ([email protected])2 free.liftfc (Ask (" How is")" //> Res1:scalaz. Free.freec[exercises.freelift.interact,string] = Suspend ([email protected])
Let's look at the LIFTFC function definition:
/** /+ Ma) (implicit ma:unapply[functor, MA]): Free[ma. M, MA. A] = LIFTF (MA (value)) (MA). TC) /** * = liftfu (Coyoneda lift s)
Coyoneda lift S Returns the result Coyoneda[s,a], liftfu unapply can be converted to coyoneda[s,a] and provided to S[a. Look at this section of unapply:
/**unpack A value of type ' m0[a0, B0] ' into types ' [A]m0[a, B0] ' and ' a ', given an instance of ' TC '*/ Implicitdef Unapplymab1[tc[_[_]], m0[_, _], A0, B0] (Implicittc0:tc[({typeλ[α] =m0[α, B0]}) #λ]): UNAPPLY[TC, M0[A0, B0]] {type m[x]=m0[x, B0] Type A=A0}=NewUNAPPLY[TC, M0[A0, B0]] {type m[x]=m0[x, B0] Type A=A0 def TC=TC0 def Leibniz=REFL}/**unpack A value of type ' m0[a0, B0] ' into types ' [b]m0[a0, b] ' and ' B ', given an instance of ' TC '*/ Implicitdef Unapplymab2[tc[_[_]], m0[_, _], A0, B0] (Implicittc0:tc[({typeλ[α] =M0[a0,α]}) #λ]): UNAPPLY[TC, M0[A0, B0]] {type m[x]=m0[a0, X] Type A=B0}=NewUNAPPLY[TC, M0[A0, B0]] {type m[x]=m0[a0, X] Type A=B0 def TC=TC0 def Leibniz=REFL}
All right. But think again, one is functor interact and what kind of? That ask must return a value, and this value should be a free, which actually represents the next operation:
1 Package Exercises2 Import Scalaz._3 Import Scalaz._4 Import Scala.language.higherKinds5 ObjectInteract {6Trait interact[+A]7 Case classAsk[next] (prompt:string, n:string =Next) extends Interact[next]8 Case classTell[next] (msg:string, n:next) extends Interact[next]9 Ten ObjectInterfunctor extends Functor[interact] { Onedef Map[a,b] (Ia:interact[a]) (f:a = B): interact[b] =ia Match { A CaseTell (m,n) =Tell (M, f (n)) - CaseG:ask[a] =Ask[b] (g.prompt, G.N andthen f) - } the}
So ask returns the next type value, which should be a free, representing the next operation.
Scalaz (+)-Free:lift-monad production line