设为首页 加入收藏

TOP

Scalaz(28)- ST Monad :FP方式适用变量(二)
2017-10-10 12:13:18 】 浏览:8949
Tags:Scalaz Monad 方式 适用 变量
ewVar[S](3) 8 x <- r.mod {_ + 2} 9 } yield x //> e1: [S]=> scalaz.effect.ST[S,scalaz.effect.STRef[S,Int]] 10 11 def e2[S] = for { 12 r <- newVar[S](3) 13 x <- r.mod {_ + 2} 14 y <- x.read 15 } yield y //> e2: [S]=> scalaz.effect.ST[S,Int] 16 17 def e3[S] = for { 18 arr <- newArr[S,Int](5,0) 19 _ <- arr.write(0,3) 20 _ <- arr.write(1,2) 21 _ <- arr.update ((a: Int,b: Int) => a + b, 2, 4) 22 r <- arr.freeze 23 } yield r //> e3: [S]=> scalaz.effect.ST[S,scalaz.ImmutableArray[Int]]

 

newVar[S](3)以状态S新建一个Int存放地址并存入值3。mod操作返回ST[S,STRef[S,Int]],返回的是个地址(reference),而read返回的是ST[S,Int],则是个值。首先注意e1[S],e2[S],e3[S]它们都附带了独立状态标签S。

现在我们需要从ST Monad里把运算结果取出来。从上面的分析我们可能面对两种方式:ST[S,A], ST[S,STRef[S,A]]。从ST[S,A]里取出的是一个A类型的值,而从ST[S,STRef[S,A]]里取出的是个内存地址。可以预见,如果我们通过某些方式能获取一个内存地址的话,就有可能在函数体外对地址内的值进行修改,也就造成了副作用的产生。Scalaz的解决方法是通过高阶类参数多态(2nd-rank parameteric polymorphism),利用编译器(compiler)对ST[S,STRef[S,A]]这样的读取操作进行拒绝编译。下面我们看看示范结果:
1 runST(new Forall[({type l[x] = ST[x, Int]})#l]{def apply[S] = e2[S]}) 2                                                   //> res0: Int = 5 3 //runST(new Forall[({type l[x] = ST[x, Int]})#l]{def apply[S] = e1[S]}) 4 //type mismatch; found : scalaz.effect.ST[S,scalaz.effect.STRef[S,Int]] required: scalaz.effect.ST[S,Int] 
e1返回ST[S,STRef[S,A]],表达式new Forall[({type l[x] = ST[x, Int]})#l]{def apply[S] = e1[S]}无法通过编译。在这里Forall是个高阶类参数多态类,定义如下:
/** A universally quantified value */ trait Forall[P[_]] { def apply[A]: P[A] }
我们再重新组织一些上面的代码,使大家可以看的更清楚一点:

 

1 type ForallST[A] = Forall[({type l[x] = ST[x,A]})#l] 2 runST(new ForallST[Int]{ def apply[S] = e2[S] })  //> res0: Int = 5 3 //runST(new ForallST[Int]{def apply[S] = e1[S]}) 4 //type mismatch; found : scalaz.effect.ST[S,scalaz.effect.STRef[S,Int]] required: scalaz.effect.ST[S,Int]

 

从错误信息可以得出:编译器期待的类型是ST[S,Int], ST[S,STRef[S,Int]]是产生类型错误。利用高阶类参数多态类f,只有new Forall { def apply[A] >>> ST[S,A] }这样的款式才能通过编译。
与State Monad比较,ST Monad并不包含为获取运算值而设的run函数。ST Monad在类型外定义了读取运算值的函数runST。
runST方法的定义如下:
  /**Run a state thread */ def runST[A](f: Forall[({type λ[S] = ST[S, A]})#λ]): A = f.apply.apply(ivoryTower)._2
State Monad获取运算值的方式是这样的:someState.run(svalue),svalue是个S类型值,是状态初始值。我们已经了解到所有的变量操作函数都没有使用S类型值,所以上面的f.apply.apply(ivoryTower)中这个ivoryTower是个没有意义的随意类型值,我们不需要注入任何S值去获取运算结果值。

 

 

 

 

 

 

 

 

 

 

 

 

 

首页 上一页 1 2 下一页 尾页 2/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇atitit.编程语言?类与对象的?扩展.. 下一篇kafka使用getOffsetsBefore()获取..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目