设为首页 加入收藏

TOP

Scalaz(42)- Free :FreeAp-Applicative Style Programming Language(一)
2017-10-10 12:12:55 】 浏览:7822
Tags:Scalaz Free FreeAp Applicative Style Programming Language

  我们在前面花了几期时间讨论Free Monad,那是因为FP既是Monadic programming,Free Monad是FP模式编程的主要方式。对我们来说,Free Monad代表着fp从学术探讨到实际应用的转变,因为我们已经示范了如何用Free Monad的算式算法关注分离模式来实现真正的软件编程。但是美中不足的是用Free Monad只能编写流程式的程序;我们只能一步一步编译这种程序而无法实现并行运算以及在编译之前对程序结果进行分析或转换等。这种特性可以从Monad的运算函数flatMap的函数款式里看出:def flatMap(fa: F[A])(f: A=>F[B]):F[B]。如果F[A]代表当前程序、F[B]就是下一个程序,而下一个程序的产生依赖于F[A]运算结果,一个runtime值。在没有完成F[A]的运算之前我们无法得知F[B]的任何信息。所以又说Monadic程序结构是动态的。我们看到Free Monad功能十分强大:可以用Free Monad来实现任何程序,只不过这些程序结构都是动态的。动态结构程序对解决某些类型的问题在效率上可能不如静态结构的程序。我们可以用Applicative来产生静态结构的程序,这个从Applicative的运算函数ap可以看得出来:def ap(f: F[A=>B])(F[A]):F[B]。我们可以这样看ap:F[A=>B]是第一段程序,F[A]是下一段程序,而F[B]是结果程序。 第一第二段程序都不依赖任何运算值,所以我们可以先构建这些程序然后在任何时候对这些程序进行编译。由于所有程序都是固定预知而互不影响的,所以非常适合并行运算。

与Free Monad相似,Free Applicative Functor也是Applicative的结构化。下面是scalaz对FreeAp的定义:scalaz/FreeAp.scala

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结构链条。

实现了Applicative的结构化后我们就可以沿袭Free Monad的算式算法关注分离模式先编写描述功能的程序然后再对程序进行编译,只不过FreeAp程序不再是在Monadic for-comprehension内的行令编程,而是一连串的ap类函数了。与Free Monad一致,我们同样用ADT来模拟applicative编程语法,然后用ap函数把ADT链接起来成为程序。我们借用scalaz.example/FreeApUsage.scala来解译:

1、定义ADT: 这里是个解析(parse)数据类型的代数语法

  // 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"))((_, _, _))

可以看到上面的Applicative编程就是用|@|把FreeAp结构链接起来,然后跟着把FreeAp之间的运算函数提供进去。我们知道F[A]|@|F[B]还是返回FreeAp[F,C]。也就是说这个程序的结果可以和其它FreeAp进行组合。我们可以看看下面的示范:

 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: Str
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇scala学习手记3 - var和val 下一篇scala学习手记4 - Java基本类型对..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目