# Scalaz（32）－ Free ：lift

`/** A free operational monad for some functor `S`. Binding is done using the heap instead of the stack,* allowing tail-call elimination. */sealed abstract class Free[S[_], A] {.../** Return from the computation with the given value. */private[scalaz] case class Return[S[_], A](a: A) extends Free[S, A]/** Suspend the computation with the given suspension. */private[scalaz] case class Suspend[S[_], A](a: S[Free[S, A]]) extends Free[S, A]...`

1、Free[S[_],A]可以代表一个运算

` /** Suspends a value within a functor in a single step. Monadic unit for a higher-order monad. */def liftF[S[_], A](value: => S[A])(implicit S: Functor[S]): Free[S, A] =Suspend(S.map(value)(Return[S, A]))`

liftF可以把一个S[A]升格成Free[S,A]。我们用个例子来证明：

` 1 package Exercises2 import scalaz._3 import Scalaz._4 import scala.language.higherKinds5 import scala.language.implicitConversions6 object freelift {7 trait Config[+A] {8 def get: A9 }10 object Config {11 def apply[A](a: A): Config[A] = new Config[A] { def get = a}12 implicit val configFunctor = new Functor[Config] {13 def map[A,B](ca: Config[A])(f: A => B) = Config[B](f(ca.get))14 }15 }1617 val freeConfig = Free.liftF(Config("hi config")) //> freeConfig : scalaz.Free[Exercises.freelift.Config,String] = Suspend([email protected])`

`1 trait Interact[+A] //Console交互2 //println(prompt: String) then readLine 返回String3 case class Ask(prompt: String) extends Interact[String]4 //println(msg: String) 不反回任何值5 case class Tell(msg: String) extends Interact[Unit]`

`1 Free.liftFC(Tell("hello")) //> res0: scalaz.Free.FreeC[Exercises.freelift.Interact,Unit] = Suspend([email protected])2 Free.liftFC(Ask("how are you")) //> res1: scalaz.Free.FreeC[Exercises.freelift.Interact,String] = Suspend([email protected])`

` /** A version of `liftF` that infers the nested type constructor. */def liftFU[MA](value: => MA)(implicit MA: Unapply[Functor, MA]): Free[MA.M, MA.A] =liftF(MA(value))(MA.TC)/** A free monad over a free functor of `S`. */def liftFC[S[_], A](s: S[A]): FreeC[S, A] =liftFU(Coyoneda lift s)`

Coyoneda lift s 返回结果Coyoneda[S,A], liftFU用Unapply可以把Coyoneda[S,A]转化成S[A]并提供给liftF。看看Unapply这段：

` /**Unpack a value of type `M0[A0, B0]` into types `[a]M0[a, B0]` and `A`, given an instance of `TC` */implicit def unapplyMAB1[TC[_[_]], M0[_, _], A0, B0](implicit TC0: TC[({type λ[α] = M0[α, B0]})#λ]): Unapply[TC, M0[A0, B0]] {type M[X] = M0[X, B0]type A = A0} = new Unapply[TC, M0[A0, B0]] {type M[X] = M0[X, B0]type A = A0def TC = TC0def leibniz = refl}/**Unpack a value of type `M0[A0, B0]` into types `[b]M0[A0, b]` and `B`, given an instance of `TC` */implicit def unapplyMAB2[TC[_[_]], M0[_, _], A0, B0](implicit TC0: TC[({type λ[α] = M0[A0, α]})#λ]): Unapply[TC, M0[A0, B0]] {type M[X] = M0[A0, X]type A = B0} = new Unapply[TC, M0[A0, B0]] {type M[X] = M0[A0, X]type A = B0def TC = TC0def leibniz = refl}`

` 1 package Exercises2 import scalaz._3 import Scalaz._4 import scala.language.higherKinds5 object interact {6 trait Interact[+A]7 case class Ask[Next](prompt: String, n: String => Next) extends Interact[Next]8 case class Tell[Next](msg: String, n: Next) extends Interact[Next]910 object interFunctor extends Functor[Interact] {11 def map[A,B](ia: Interact[A])(f: A => B): Interact[B] = ia match {12 case Tell(m,n) => Tell(m, f(n))13 case g: Ask[A] => Ask[B](g.prompt, g.n andThen f)14 }15 }`