设为首页 加入收藏

TOP

Scalaz(41)- Free :IO Monad-Free特定版本的FP语法(二)
2017-10-10 12:13:00 】 浏览:11080
Tags:Scalaz Free Monad 特定 版本 语法
ase
(nw, a) => f(a)(nw) }) ... /** Construct an IO action from a world-transition function. */ def io[A](f: Tower[IvoryTower] => Trampoline[(Tower[IvoryTower], A)]): IO[A] = new IO[A] { private[effect] def apply(rw: Tower[IvoryTower]) = Free(() => f(rw)) }

可以看得出io[A](...)就是IO的构建器(constructor)。IO[A]类型是Free[Function0,A] = Free(() => f(rw)),最终就是一个Trampoline,这个可以从下面的apply看得出来:

object IO extends IOInstances { def apply[A](a: => A): IO[A] = io(rw => return_(rw -> a)) ...

上面的Tower[IvoryTower]是状态切换函数的输入类型,不参与实际运算(不在任何运算中调用如: rw -> a),起一种状态标签作用(state tag)。主要提供给编译器(compiler)做类型安全用。实际上这个状态切换函数就是一个延迟运算值 => A。io把这个值挂到Free的suspend状态: 

/** Suspend the given computation in a single step. */ def return_[S[_], A](value: => A)(implicit S: Applicative[S]): Free[S, A] = liftF[S, A](S.point(value))
 
 

再看看IO的运算方式:

 

sealed abstract class IO[A] { private[effect] def apply(rw: Tower[IvoryTower]): Trampoline[(Tower[IvoryTower], A)] import IO._ /** * Runs I/O and performs side-effects. An unsafe operation. * Do not call until the end of the universe. */ def unsafePerformIO(): A = apply(ivoryTower).run._2

 

先用apply建Trampoline,再运行Free.run(Trampoline[A]=Free[Function0,A])。注意,我们并没有采用这个Tower[IvoryTower]。再者,函数unsafePerformIO是通过private函数apply先构建了Trampoline后再进行运算的。换言之IO Monad的用户是无法自定义算法(interpreter)的。我们前面曾经把Free描述成可以自定义F[A]编程语言的数据结构,那么IO[A]就是一种固定的FP编程语言,它只有unsafePerformIO一种算法(interpreter)。

IO Monad可以使我们更方便地在IO这个壳子里进行我们熟悉的行令编程(imperative programming),因为我们只需要把行令程序直接放进IO里就行了。看看下面这些例子:

1 val hello = print("hello ").point[IO]             //> hello : scalaz.effect.IO[Unit] = scalaz.effect.IO$$anon$6@145eaa29
2 val world = IO (print("world,"))                  //> world : scalaz.effect.IO[Unit] = scalaz.effect.IO$$anon$6@57c758ac
3 val howareyou = io {rw => return_(rw -> println("how are you!"))} 4                                                   //> howareyou : scalaz.effect.IO[Unit] = scalaz.effect.IO$$anon$6@a9cd3b1
5 val greeting = hello |+| world |+| howareyou      //> greeting : scalaz.effect.IO[Unit] = scalaz.effect.IO$$anon$6@481a996b
6 greeting.unsafePerformIO                          //> hello world,how are you!

这个例子示范了用三种方式把副作用语句print升格成IO。不要被IO[A]的IO字面误导了,IO[A]的这个A不一定是副作用命令,任何行令编程使用的语句都可以放人IO[_],包括变量申明、赋值、文件读写等。所以我们说IO Monad就是在FP模式中进行行令编程的通用方式。可以想象我们可能会在IO这个壳子内进行我们熟悉的程序编写。那么IO Monad到底能不能符合在FP环境内的行令编程要求呢?我们可以用几个例子来对流程控制(flow control),跟踪记录(logging)即异常处理(exception handling)等方面进行测试示范:

 

 1 import scalaz._  2 import Scalaz._  3 import effect._  4 import IO._  5 import Free._  6 import scala.language.higherKinds  7 import scala.language.implicitConversions  8 
 9 object IOPrg { 10   def div(dvdn: Int, dvsor: Int): IO[Int] = 
11     IO(dvdn / dvsor) 12   val ioprg: IO[Int] = for { 13     _ <- putLn("enter dividend:") 14     dvdn <- readLn 15     _ <- putLn("enter divisor:") 16     dvsor <- readLn 17     quot <- div(dvdn.toInt, dvsor.toInt) 18     _ <- putLn(s"the result:$quot") 19   } yield quot 20 } 21 
22 object IOMonadDemo extends App { 23  import IOPrg._ 24  ioprg.unsafePerformIO() 25 }

 

"enter dividend:"
10
"enter divisor:"
5
"the result:2"

ioprg是一段包含了带副作用语句的程序。所有副作用延迟到unsafePerformIO()才正真产生。现在我们先示范流程控制,试着提早跳出这个for-loop。这不就是option在for-comprehension的作用吗。我们需要在IO[A]这种Monad之上增加Option的作用,可以用Monad Transform

首页 上一页 1 2 3 4 5 下一页 尾页 2/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇PageRank基于Spark实现介绍 下一篇Scala学习手记1 - 快速体验

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目