# Scalaz（42）－ Free ：FreeAp－Applicative Style Programming Language

274人阅读 评论(0)

sealed abstract class FreeAp[F[_],A] {
...
private [scalaz] case class Pure[F[_],A](a: A) extends FreeAp[F,A]
private abstract case class Ap[F[_],A]() extends FreeAp[F,A] {
type I
val v: () => F[I]
val k: () => FreeAp[F, I => A]
}


FreeAp是一种有两种状态的数据类型：case class Pure(a: A)和 case class Ap(){v: ()=>F[I], k: ()=> FreeAp[F, I=>A]}，其中Pure既是Return，包嵌一个运算结果值A，Ap结构内的k代表了下一个FreeAp，实现一个以Pure为终结的FreeAp结构链条。

  // An algebra of primitive operations in parsing types from Map[String, Any]
sealed trait ParseOp[A]
case class ParseInt(key: String) extends ParseOp[Int]
case class ParseString(key: String) extends ParseOp[String]
case class ParseBool(key: String) extends ParseOp[Boolean]


2、升格：Lift to FreeAp

  // Free applicative over Parse.
type Parse[A] = FreeAp[ParseOp, A]

// Smart constructors for Parse[A]
def parseInt(key: String) = FreeAp.lift(ParseInt(key))
def parseString(key: String) = FreeAp.lift(ParseString(key))
def parseBool(key: String) = FreeAp.lift(ParseBool(key))


FreeAp.lift 可以把任何F[A]升格成FreeAp[F,A]:

  /** Lift a value in F into the free applicative functor on F */
def lift[F[_],A](x: => F[A]): FreeAp[F, A] = FreeAp(x, Pure((a: A) => a))


3、AST: Applicative编程

  // An example that returns a tuple of (String, Int, Boolean) parsed from Map[String, Any]
val successfulProg: Parse[(String, Int, Boolean)] =
(parseString("string") |@| parseInt("int") |@| parseBool("bool"))((_, _, _))

// An example that returns a tuple of (Boolean, String, Int) parsed from Map[String, Any]
val failedProg: Parse[(Boolean, String, Int)] =
(parseBool("string") |@| parseString("list") |@| parseInt("bool"))((_, _, _))


 object algebra {
sealed trait ConfigF[A]

case class ConfigInt   [A](field: String, value: Int     => A) extends ConfigF[A]
case class ConfigFlag  [A](field: String, value: Boolean => A) extends ConfigF[A]
case class ConfigPort  [A](field: String, value: Int     => A) extends ConfigF[A]
case class ConfigServer[A](field: String, value: String  => A) extends ConfigF[A]
case class ConfigFile  [A](field: String, value: String  => A) extends ConfigF[A]
case class ConfigSub   [A](field: String, value: FreeAp[ConfigF, A])   extends ConfigF[A]
}

object dsl {
import algebra._

type Dsl[A] = FreeAp[ConfigF, A]

private def lift[A](value: ConfigF[A]): Dsl[A] = FreeAp.lift[ConfigF, A](value)

def int   (field: String): Dsl[Int]     = lift(ConfigInt   (field, identity))
def flag  (field: String): Dsl[Boolean] = lift(ConfigFlag  (field, identity))
def port  (field: String): Dsl[Int]     = lift(ConfigPort  (field, identity))
def server(field: String): Dsl[String]  = lift(ConfigServer(field, identity))
def file  (field: String): Dsl[String]  = lift(ConfigFile  (field, identity))
def sub[A](field: String)
(value: Dsl[A])               = lift(ConfigSub   (field, value))
}


  case class AuthConfig(port: Int, host: String)
case class ServerConfig(logging: Boolean, auth: AuthConfig)

val authConfig   = (int("port") |@| server("host"))(AuthConfig)
val serverConfig = (flag("logging") |@| sub("auth")(authConfig))(ServerConfig)


4、Interpret: 翻译，把描述的功能对应到具体的实现方法上，还是用NaturalTransformation的方式把F[A]对应到G[A]：

  def parseOpt[A: ClassTag](a: Any): Option[A] =
a match {
case a: A => Some(a)
case _ => None
}

// Natural transformation to Option[A]
def toOption(input: Map[String, Any]): ParseOp ~> Option =
new (ParseOp ~> Option) {
def apply[A](fa: ParseOp[A]) = fa match {
case ParseInt(key) =>
input.get(key).flatMap(parseOpt[java.lang.Integer](_).map(x => (x: Int)))
case ParseString(key) => input.get(key).flatMap(parseOpt[String])
case ParseBool(key) =>
input.get(key).flatMap(parseOpt[java.lang.Boolean](_).map(x => (x: Boolean)))
}
}

// Natural transformation to ValidationNel[String, A]
type ValidatedParse[A] = ValidationNel[String, A]
def toValidation(input: Map[String, Any]): ParseOp ~> ValidatedParse =
new (ParseOp ~> ValidatedParse) {
def apply[A](fa: ParseOp[A]) = fa match {
case s@ParseInt(_) => toOption(input)(s)
.toSuccessNel(s"${s.key} not found with type Int") case s@ParseString(_) => toOption(input)(s) .toSuccessNel(s"${s.key} not found with type String")
case i@ParseBool(_) => toOption(input)(i)
}
}


ParseOp ~> Option：翻译成Option类型。注意：input.get(key)返回Option，parseOpt同样返回Option

ParseOp ~> ValidatedPase：翻译成Validation类型。注意：无论如何，运算过程是不会中断的，ValidationNel中会记录所有错误信息

5、运算：runner，用折叠式来对一串FreeAp结构的每一个单元进行运算，还是叫做foldMap：

  /**
* The canonical natural transformation that interprets this free
* program by giving it the semantics of the applicative functor G.
* Not tail-recursive unless G is a free monad.
*/
def foldMap[G[_]:Applicative](f: F ~> G): G[A] =
this match {
case Pure(x) => Applicative[G].pure(x)
case x@Ap() => Applicative[G].ap(f(x.v()))(x.k() foldMap f)
}


  // An example that returns a tuple of (String, Int, Boolean) parsed from Map[String, Any]
val successfulProg: Parse[(String, Int, Boolean)] =
(parseString("string") |@| parseInt("int") |@| parseBool("bool"))((_, _, _))

// An example that returns a tuple of (Boolean, String, Int) parsed from Map[String, Any]
val failedProg: Parse[(Boolean, String, Int)] =
(parseBool("string") |@| parseString("list") |@| parseInt("bool"))((_, _, _))

// Test input for programs
val testInput: Map[String, Any] =
Map("string" -> "foobar", "bool" -> true, "int" -> 4, "list" -> List(1, 2))

// Run that baby
println(successfulProg.foldMap(toOption(testInput)))
println(successfulProg.foldMap(toValidation(testInput)))
println(failedProg.foldMap(toOption(testInput)))
println(failedProg.foldMap(toValidation(testInput)))


<span style="font-size:14px;">Some((foobar,4,true))
Success((foobar,4,true))
None
</span>

0
0

* 以上用户言论只代表其个人观点，不代表CSDN网站的观点或立场
个人资料
• 访问：67430次
• 积分：2391
• 等级：
• 排名：第17462名
• 原创：179篇
• 转载：0篇
• 译文：0篇
• 评论：2条
评论排行
最新评论