scala函数式编程笔记: 纯函数式状态
scala函数式编程:纯函数式状态读书笔记
Overview:
- 带状态的方法的声明式实现可能带有副作用,难以保持引用透明。
- 以纯函数式的方式实现带状态的函数的关键在于让状态更新是显式的,不要以副作用方式更新状态,而是连同生成的值一起返回一个新的状态。即把状态的隐式更改暴露出去。
- 例:函数nextInt返回改变后的新状态nextRNG
trait RNG{def nextInt: (Int,RNG)
}case class SimpleRNG(seed: Long) extends RNG{//返回一个随机Int值,纯函数式实现,返回新的SimpleRNGdef nextInt: (Int,RNG) = {val newSeed = (seed * 0x5DEECE66DL + 0xBL) & 0xFFFFFFFFLval nextRNG = SimpleRNG(newSeed)val n = (newSeed >>> 16).toInt(n, nextRNG)}//带有副作用的实现,currentSeed的更新是隐含的val currentSeed = seeddef nextInt2: Int = {val newSeed = (currentTime * 0x5DEECE66DL + 0xBL) & 0xFFFFFFFFLcurrentSeed = newSeedval n = (newSeed >>> 16).toIntn}
}
组合子:
- 组合子是一个高阶函数,可以看作函数的类型别名,用来避免显示地进行状态传递。
- RNG=>(A,RNG)是一个函数,接受旧RNG,得到新的RNG,状态行为可以通过组合子来表示,如组合子Rand:
type Rand[+A] = RNG => (A, RNG)
- 实例分析:
val int: Rand[Int] = _.nextInt
_.nextInt 等价于 RNG => (Int,RNG)
。即接受一个RNG类型参数并返回一个(Int,RNG)类型元组的函数。- 而
Rand[Int]
是函数RNG => (Int,RNG)
的类型别名。
使用组合子来组合状态行为:
- 即对于有状态的函数,首先将其参数和返回值包装为组合子。然后通过map,flatMap等来以纯函数的形式实现该函数。其中f,g等即该函数。
- 一个状态行为: s(rng1: RNG)返回(v: Int,rng2: RNG)
def map[A,B](s: Rand[A])(f: A => B): Rand[B] = rng1 => {val (v,rng2) = s(rng1)(f(v),rng2)}def flatMap[A,B](f: Rand[A)(g: A => Rand[B]): Rand[B] = rng => {(v,r) = f(rng)g(v)(r)}
- 组合2个状态行为:
def map2[A,B,C](ra: Rand[A], rb: Rand[B])(f: (A,B) => C): Rand[c] = rng1 => {val (v1,rng2) = ra(rng1)val (v2,rng3) = rb(rng2)(f(v1,v2),rng3)}
- 组合一序列状态行为:
def unit[A](a: A): Rand[A] = rng => (a,rng)def sequence[A](fs: List[Rand[A]]): Rand[List[A]] =List.foldRight(fs,unit(List[A())))((x,y) => map2(x,y)((a,b) => Cons(a,b)))
通用的状态行为数据类型
- 前边组合子状态是类型RNG。我们来把组合子泛化。S表示任何状态。
type State[+A,S] = S => (A,S)
- 我们也可以将泛化的组合子定义为一个class。State[+A,S]中定义的函数是实现函数式风格的任何状态机或带状态程序所需的全部工具。
case class State[+A,S](run: S => (A,S)) extends AnyVal{def map[B](f: A => B): State[B,S] = State(s => {val (i,r) = run(s)(f(i),r)})def map2[B,C](b: State[B,S])(f: (A,B) => C): State[C,S] = State(s => {val (v1,s1) = run(s)val (v2,s2) = b.run(s1)(f(v1,v2),s2)})//def _map2[B,C](b: State[B,S])(f: (A,B) => C): State[C,S] =// flatMap(x => b.map(y => f((x,y))))def flatMap[B](f: A => State[B,S]): State[B,S] = State(s => {val (v,s1) = run(s)f(v).run(s1)})
}object State{def unit[A,S](x: A): State[A,S] = State(s => (x,s))def sequence[A,S](ls: List[State[A,S]]): State[List[A],S] =List.foldRight(ls,unit[List[A],S](List()))((x,y) => x.map2(y)(Cons(_,_)))def modify[S](f: S => S): State[Unit,S] = for {s <- get //获取当前状态分配给s_ <- set(f(s)) //设置新状态} yield ()def get[S]: State[S,S] = State(s => (s,s))def set[S](s: S): State[Unit,S] = State(_ => ((), s))
}
应用实例
- 题目
EXERCISE 13 (hard): To gain experience with the use of State, implement a simulation of a simple candy dispenser. The machine has two types of input: You can insert a coin, or you can turn the knob to dispense candy. It can be in one of two states: locked or unlocked. It also tracks how many candies are left and how many coins it contains.
[外链图片转存失败(img-Amx9zUUg-1564306192450)(http://oxaz2p2ac.bkt.clouddn.com/Screen Shot 2017-10-04 at 10.21.02 PM.png)]
- 标准答案:
https://github.com/fpinscala/fpinscala/blob/master/answerkey/state/11.answer.scala - 我的解法: https://github.com/haiboself/Scala-learning/tree/master/src/PureFunctionalState
- 参考资料:
- https://stackoverflow.com/questions/41012375/functional-programing-in-scala-simulatemachine/41328969#41328969
- https://groups.google.com/forum/#!topic/scala-functional/8iHaSFPPjgw
package PureFunctionalStateimport datastruct._sealed trait Input
case object Coin extends Input
case object Turn extends Inputcase class Machine(locked: Boolean, candies: Int, coins: Int) {/** 有副作用的实现* 实际上Machine的状态就是自己的属性,所以返回值类型Machine实际上既是值又是状态* 所以这个实现应该可以看作纯函数式的实现*/def simulateMachine(inputs: List[Input]): Machine = {List.foldLeft(inputs,Machine(locked,candies,coins))((x, y) => (x,y) match {case (Coin,Machine(true,cands,x)) if cands>0 => Machine(false,cands,x)case (Turn,Machine(false,cands,x)) if cands>0 => Machine(true,cands-1,x+1)case _ => y})}/** 纯函数式实现。* modify返回State[Unit,Machine]。modify从旧状态生成新状态,也就是据inputs的每个输入得到一个新的Machine* map返回List[State[Unit,Machine]]* sequence返回State[List[Unit],Machine]*/def simulateMachine3(inputs: List[Input]): State[(Int, Int),Machine] = for {_ <- State.sequence(List.map(inputs)(i => State.modify((s: Machine) => (i, s) match {case (_, Machine(_, 0, _)) => scase (Coin, Machine(false, _, _)) => scase (Turn, Machine(true, _, _)) => scase (Coin, Machine(true, candy, coin)) =>Machine(false, candy, coin + 1)case (Turn, Machine(false, candy, coin)) =>Machine(true, candy - 1, coin)})))s <- State.get} yield (s.candies, s.coins)}object TestMachine{def main(args: Array[String]): Unit = {val machine = Machine(true,10,0)val ls = List(Coin,Turn,Turn,Coin,Turn,Coin,Coin,Turn)println(machine.simulateMachine(ls))println(machine.simulateMachine3(ls).run(machine))}
}
scala函数式编程笔记: 纯函数式状态相关推荐
- JavaScript函数式编程(纯函数、柯里化以及组合函数)
JavaScript函数式编程(纯函数.柯里化以及组合函数) 目录 JavaScript函数式编程(纯函数.柯里化以及组合函数) 前言 1.纯函数 1.1.纯函数的概念 1.2.副作用 1.3.纯函数 ...
- 函数式编程笔记 01
Cousera 上 Functional Programming Prinples in Scala 的笔记. 编程范式 范式描述了某些科学学科中独特的概念或者思考模式. 主要的编程范式: 命令式编程 ...
- 闭关之 C++ 函数式编程笔记(一):函数式编程与函数对象
目录 前言 第一章 函数式编程简介 1.1 命令式与声明式编程比较 1.2 纯函数(Pure functions) 1.2.1 避免可变状态 1.3 以函数方式思考问题 1.4 函数式编程的优点 1. ...
- 闭关之 C++ 函数式编程笔记(四):monad 和 模板元编程
目录 第十章 monad 注意 10.1 仿函数并不是以前的仿函数 10.1.1 处理可选值 10.2 monad: 更强大的仿函数 10.3 基本的例子 10.4 range 与 monad 的嵌套 ...
- java8函数式编程笔记-科里化
java函数式编程-科里化 什么是函数? 在数学上,函数的定义为"它接受零个或多个参数,生成一个或多个结果" 而在java8中,函数的定义为像数学函数一样没有副作用的函数 复制代码 ...
- python函数式编程模式_函数式编程指引
概述¶ 本章介绍函数式编程的基本概念.如您仅想学习 Python 语言的特性,可跳过本章直接查看 迭代器. 编程语言支持通过以下几种方式来解构具体问题: 大多数的编程语言都是 过程式 的,所谓程序就是 ...
- java函数式编程_说说函数式编程的那些事
今天这篇文章我们主要来聊聊函数式编程的思想. 函数式编程有用吗? 什么是函数式编程? 函数式编程的优点. 总所周知 JavaScript 是一种拥有很多共享状态的动态语言,慢慢的,代码就会积累足够的复 ...
- java函数式编程例子_java函数式编程Lambda表达式的示例(一)
函数式编程是时下比较流行的编程方式了,很多新兴的编程语言都对函数式编程有了比较好的支持,她有别于传统的命令式编程,可以将函数(执行代码的过程)作为参数进行传递.JAVA也意识到了函数式编程的重要性,在 ...
- python语言支持函数式编程_python是函数式语言么
函数式编程:functional,是一种编程范式. 函数式编程的特点:1. 把计算视为函数而非指令 2. 纯函数式编程:不需要变量,没有副作用,测试简单 3. 支持高阶函数,代码简洁 Python支持 ...
最新文章
- deepin终端编译c程序_C/C++知识点之Ubuntu / Debian / Deepin等 Sublime Text 3 配置C++环境(一键编译运行,格式化代码)...
- Java黑皮书课后题第10章:**10.28(实现StringBuilder类)在Java库中提供了StringBuilder类。给出你对下面方法的实现(将新类命名为MyStringBuilder2)
- 数字几何处理作业1:编程实现三角网格上高斯曲率和平均曲率的计算编程部分
- 构建高性能分布式搜索引擎(Wcf-基础篇)一
- Angular URL地址参数改变,视图不更新的解决办法(监听URL变化,重新加载数据方法)
- Lesson 04:类和对象,类的成员变量、成员方法、构造方法
- 泛微oa连接mysql,泛微OA 数据库维护笔记(e-cology)
- 【渝粤题库】陕西师范大学202161社会保障学 作业(高起专)
- 【Python】 matplotlib 以pdf形式保存图片
- 凭借近2亿的年销量,小米三年超越苹果的可能性有多大?
- HDU 6148 Valley Numer(数位DP)
- nasm汇编器的安装与基本使用方法
- 边际生产力理论(转载)
- Linux下访问处理器硬件信息原理:图形化工具RWLinux的诞生
- ERP项目文档--想到用时方恨少
- C语言程序设计(第三版)何钦铭著 习题4-1
- linux运行倩女,在Linux下可用Wine安装和运行新倩女幽魂、迷你世界
- 徐盛:软件测试新趋势从超人时代到智慧测试时代
- python按列索引提取文件夹内所有excel指定列汇总
- ubuntu不支持安装搜狗_Ubuntu 16.04安装搜狗拼音输入法错误问题的解决方法