Skip to content

monad与副作用,不纯函数 #7

@boboyada

Description

@boboyada

一、 有本书,是scala 函数编程,里面有个例子:
有两个玩家p1和p2, 写一个函数,把p1,p2中得分高的打印出来。如下:
case class Player(name:String,score:Int) //这是一个Player的类,有两个属性,玩家姓名和得分

   def contest(p1:Player,p2:Player):Unit =     
		if(p1.score > p2.score)
			println("${p1.name} is the winner!")           //玩家1是赢家
			
			else if (p2.score >p1.score) 
			println("$(p2.name} is the winner!")           //玩家2是赢家
			
		else 
			println("It'a draw")                           //平局
			
上面的代码中,println函数是有副作用的,因为是要输出到IO里。

所以导致contest 这个方法是不纯的,有副作用,不容易测试。于是认为,需要把这个函数contest 进行修改,抽象出不纯的,变成一个由若干个纯函数组合模式。可以采用monad单子来抽象。
改进后的代码如下:

二、

case class Player(name:String,score:Int)

1.//trait类似于接口,只定义了一个方法,返回为空的意思。 描述有一个IO动作,至于这个动作什么时候执行,如何执行,则由外部来完成。
trait IO {def run:Unit}

2.纯函数,只返回赢家这个对象
def winner(p1:Player,p2:Player):Option[Player]= //Option有点类似于haskell中的Maybe
if(p1.score >p2.score) Some(p1)
else if (p1.score<p2.score ) Some(p2)
else None //平局

  1. //生成赢家所要打印出来的信息串
    def winnerMsg(p:Option[player]) :Unit= p map {
    case Player(name,_) => "$name is the winner" //模式匹配,生成赢家的要打印的信息
    } getOrElse "it's a draw //不是直接调用println 输出到屏幕

  2. //描述一个需要进行IO动作,具体的打印,则由系统的解释程序来完成
    def PrintLine(msg:String) :IO=
    new IO {def run =println(msg)}

5.最终的组合函数
def contest(p1:Player,p2:Player):IO=
PrintLine(winnerMsg(winner(p1,p2)))

于是整个contest 函数都是纯的,无副作用的,而且是可以测试的。
但是这里没有看到与单子的影子呀?
单子不是用来剥离副作用的吗?怎么个剥离呢?
你怎么理解?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions