我们是在F运算模式的壳子内对T进行计算。理论上来讲,函数式程序的运行状态也应该是在这个运算模式壳子内的,也是在F[]内更新的。那么我们就应该像函数式运算T值一样,也有一套函数式更新程序状态的方法。...曾经提到过Writer还可以被理解成一种特别的状态维护,只是目标锁定在了Log的更新。那么真正意义的状态类型State Monad又是怎样的呢?...其它函数都是用来获取新的运算值或新状态的,如:eval返回F[A],exec返回F[S2]。值得注意的是这个F必须是Functor才行,因为我们必须用map才能在F[]内更新运算值或状态。...State Monad应该需要一套读写、传递状态的方法。...这些方法可以在MonadState trait里找到:scalaz/MonadState.scala trait MonadState[F[_,_],S] extends Monad[({type f[
泛函编程与传统的行令编程在模式上最大的分别就是在泛函编程中没有变量声明(variable declaration),变量是包嵌在一个结构里的(MyData(data)),得申明这个结构(trait MyData...所以泛函编程的命令执行都是在一些结构内部进行的。Monad组件库中的组件主要支持这种结构内部运算风格。...,map,flatMap,所以我们可以在Maybe Monad的环境里实现for-comprehension的应用 1 val maybeFor: Maybe[Int] = for { 2...Monad for-comprehension内的行令运算同样需要遵循State Monad map, flatMap的类型匹配。...可以肯定这个State Monad for-comprehension内的行令运算同样需要遵循State Monad map, flatMap的类型匹配。
如果我们在程序中定义的函数和数学函数一样,不依赖可变状态,也不产生副作用,那么我们就可以很好地解决之前提到的问题。这也是为什么一些语言在语法上就鼓励不可变。...,我们显式地在 labelTree 的调用中传递了状态,并将这个过程泛化到可以处理任意标签的情况,我们此时可以发现,状态和状态的转变其实是一个非常一般的情况,对于这样的情况,我们可以构建一个新的类型专门用来表示它...而 map 方法本身是可以用 flatMap 和 unit 直接定义出来的: class StateT[X, S](val trans: S => (X, S)) { // ......,尽管我们显式地在类型上表示了状态、尽管状态依然是不可变的、尽管我们确实能获得正确的结果,但我们并没有去手工管理状态的更新,状态在 Monad 的包裹中传递。...(newRight => Branch(newLeft, newRight))) } 重新再看一下 flatMap 和 map 的实现,我们就会发现实际上是 flatMap 在帮助我们管理了状态的更新
所以sequence的行为还是依赖于List实例中flatMap的实 现方法 对于Option: sequence[A](lm: List[M[A]]): M[List[A]] >>> sequence...而且我们也实现了State类型的map, flatMap这两个函数: 1 case class State[S, A](run: S => (A, S)) { 2 def map[B](f: A...我们可以这样解释State:State[S,_]:实际上State[S,_]是一组不同S的State[A],换句话说:State不只有一个Monad实例而是一类的Monad实例。...: State[S,B] = flatMap(sa)(f) 4 } 看,在Monad类参数里糊弄了类系统后,StateMonad内部沿用了State正常表述,没任何变化。...在这个例子里我们了解了Monad的意义: 1、可以使用for-comprehension 2、支持泛函式的循序命令执行流程,即:在高阶类结构内部执行操作流程。
类型 在函数式编程中有一个巨大的兴趣领域:类型论,本书基本上完全远离了该领域。我不会深入到类型论,坦白的说,我没有深入的能力,即使干了也吃力不讨好。 但是我要说,Monad 基本上是一个值类型。...所以如果 Monad 实例出现在 Monad 操作中,它就会对 Monad 操作起短路(short-circuiting)作用。 Maybe 这个抽象概念的作用是隐式地封装了操作和无操作的二元性。...,因为,它使用一个条件来决定是选择 Maybe 的 Just(..) 还是 Nothing()。...是柯里化的,bob.map(..) 的调用传入了 bob 自身的级别(41),并且创建了一个被其余的方法包装的 Monad 实例。...在 这个 Monad 中调用的 ap(alice) 调用了 alice.map(..),并且传递给来自 Monad 的函数。
我们又说所有Monad都是Applicative,因为我们可以用flatMap来实现map2,但不是所有数据类型的flatMap都可以用map2实现,所以反之不是所有Applicative都是Monad...Applicative注重于各种类型的函数施用,也就是map。包括普通函数的施用及在高阶类型结构内的函数施用,还有多参数函数的连续施用。...既然Traversable是那么地普遍,为什么不把它抽象出来形成一个特殊的类型呢?...State能够很巧妙地对高阶数据类型结构内部元素进行函数施用同时又维护了运算状态数据。前面我们已经取得了State Nonad实例。...如果我们在游览(traverse)一个集合的过程中用State Applicative Functor对集合元素进行操作并且维护状态数据,那么将会实现强大的高阶数据类型处理功能。
特别是在调试的过程中,我们可以借助插件,任意达到每一个state状态,能够轻松的捕捉到错误是在哪一个节点出现。...return sendRequest(host, fixPath, path) } 总结 科里化和偏函数的主要用途是在组合中,这一小节主要介绍了他们的使用方法和行为。...正如你看到的,我们只是简单地调用 Task 的 map 函数,就能操作将来的值,好像这个值就在那儿似的。...Promise是Monad 需要被认为是Monad需要具备以下三个条件 拥有容器, 即Maybe、IO之类。...可以使用then方法的第二个回调或使用特殊的.catch方法捕获错误 Applicative Functor 提到了Functor和Monad而不提Applicative Functor就不完整了。
在scalaz的学习过程中,我们了解到所谓函数式编程就是monadic Programming:即用monad这样的数据类型来构建程序。...而实际可行的monadic programming就是用Free-Monad编程了。因为Free-Monad程序是真正可运行的,或者说是可以实现安全运行的,因为它可以保证在固定的堆栈内实现无限运算。...的讨论中并没能详尽地分析在什么情况下S[_]必须是个Functor。...下面我们选择能保证运算安全的方法来运算tester:首先我们需要Tester类型的Monad和RecursiveTailRecM实例: 1 import cats.Monad 2 implicit...KVStoreState[A]类型的S参数为immutable.Map[String, Any],所以我们在S转换操作时用immutable map的操作函数来构建新的map返回,典型的pure code
在前几期讨论中我们终于推导出了Free Monad。这是一个Monad工厂,它可以把任何F[A]变成Monad。可惜的是它对F[A]是有所要求的:F必须是个Functor。...Free Monad由此被称为由Functor F 产生的Monad。F必须是Functor,这个门槛使我们在使用Free Monad时很不方便。...现在的问题是如果能有个什么方法把F[A]变成Functor,就像Free Monad那样有个Free Functor就好了。...我们在liftFU函数中需要借用scalaz的Unapply类型来分解出Coyoneda, S[A]然后施用在liftF; def liftF[S[_],A](sa: S[A])(implicit S:...再试试加了State维护的IO程序: 1 case class State[S,A](runState: S => (A,S)) { 2 def map[B](f: A => B) = State
而不同类型的Monad实例则会支持不同的程序运算行为,如:Option Monad在运算中如果遇到None值则会中途退出;State Monad会确保状态值会伴随着程序运行流程直到终结;List Monad...Monad所提供的主要注入方法(injected method)是在BindOps和MonadOps里。...在MonadOps里提供的注入方法如下:scalaz/Syntax/MonadSyntax.scala 1 final class MonadOps[F[_],A] private[syntax](val...再形象一点来说上面的for loop就像F[]壳子,在for loop内可以进行申明变量,更新状态等OOP式行令编程。但这些变化(mutability)不会漏出for loop之外。...) 可以看到这个过程中有些环节已经超出了我的能力,但杠铃最终状态好像还是合理的。
之前我们曾经讨论过 ReaderWriterState Monad,它是Reader,Writer,State三个Monad的组合。...,我们可以通过Monad Transformer来灵活地组合Monad。...而我们在操作时如在for-comprehension中运算时使用的类型则必须统一为OptionT[Either,A]。 我们如何去构建Monad Transformer类型值呢?...的确,用Monad Transformer组合Monad后可以实现成员Monad的效果叠加。 不过,在实际应用中两层以上的Monad组合还是比较普遍的。...可想而知,如果遇到四层以上的Monad组合,代码会复杂成怎样。其中重点还是在各种类型的升格。
Free[S,A]是个代表Monad的最简单数据结构,它可以把任何Functor S升格成Monad。...我们同样可以简单的把Functor视为一种算法,通过它的map函数实现运算。...好了,现在我们看看如何用fold来运算prg:fold需要两个入参数:r:A=>B,一个在运算终止Return状态时运行的函数,另一个是s:S[Free[S,A]]=>B,这个函数在Suspend状态时运算入参数...在Suspend Question状态下,运算f(readLine)产生下一个运算。在这个函数里我们赋予了提示、读取正真的意义,它们都是通过IO操作println,readLine实现的。...但这个fold方法每调用一次只运算一个ADT,所以使用了递归算法连续约化Suspend直到Return。递归算法很容易造成堆栈溢出异常,不安全。下一个试试foldMap。
它不但涵盖了所有基础类型(primitive types)的泛函行为及操作,而且任何高阶类或者自定义类一旦具备Monad特性就可以与任何类型的Monad实例一样在泛函编程中共同提供一套通用的泛函编程方式...A => B): Option[B] 3 def map[A,B](pa: Par[A])(f: A => B): Par[B] 4 def map[A,B](sa: State[S,A])(f...: A => B): State[S,B] 这几个函数都具有高度相似的款式(signature),不同的是它们施用的具体数据类型。...这里的map还是抽象的,意味着还需要在具体的类型实例里实现。我们在设计unzip时是针对F的。...f(a,b) }} 9 } 看看这些map2函数:不但款式相同,实现方法也是相同的。
Scalaz提供了专门解决可变量使用问题的方法,能保证即使在并行运算的环境内各线程无法影响相互间的可变量,即ST Monad。...Monad极其相似,备有map和flatMap,所以是个Monad,能支持for-comprehension。...这正是ST Monad如何命名的:ST又可以被称为State Tag,也就是说每一项操作都有独立的状态类型S,如果S类型有所不同的话是无法调用操作函数的。...ST Monad与State Monad最大的不同是它没有run方法,也就是我们无法用ST的内部方法来获取ST[S,A]的A值。...与State Monad比较,ST Monad并不包含为获取运算值而设的run函数。ST Monad在类型外定义了读取运算值的函数runST。
在上节我们介绍了Free Monad的基本情况。可以说Free Monad又是一个以数据结构替换程序堆栈的实例。...实际上Free Monad的功能绝对不止如此,以heap换stack必须成为Free Monad的运算模式,这样我们才可以放心的使用Free Monad所产生的Monadic编程语言了。...实际上我们是用map来运行next的。这样我们就可以得出Interact的Functor实例。...还是那句话:用一个有Functor实例的类型就可以产生一个Free Monad。然后我们可以用这个产生的Monad来在for-comprehension里面编写一个算法。...这正是Free Monad功能精妙之处:我们用Monad for-comprehension来编写一段Monadic program,然后在Interpreter中赋予它具体意义:用Interpreter
所以在泛函编程模式中好像是禁止任何状态变化的(state mutation)。...程序变得复杂影响了代码的理解、维护及重复利用。 泛函编程采用的是一种处理变量状态变化的编程语言。在前面我们已经讨论过State Monad,它可以对状态进行读写。...State Monad的运作模式是:S => (A,S),即:传入一个状态S,产生一个新的值及新的状态。...我们需要实现的方法包括: 分配新的内存单元(memory cell) 读取内存单元数据 存写内存单元数据 ST是个Monad,我们可以制造一个for-comprehension的Monadic语言来进行泛函变量状态转变...把类参数S嵌入在RunnableST类内部的apply方法里。这样可以有效防止new RunnableST[STRef[Nothing,Int]]这样的语句通过编译。
在上面几期讨论中我们连续介绍了Free Monad。因为FP是纯函数编程,也既是纯函数的组合集成,要求把纯代码和副作用代码可以分离开来。...AST既是对程序功能的描述,它的组成过程也就是Monadic Programming了。在另外一个过程中,我们可以按需要去实现各种Interpreter,从而达到实际运算的目的。...我认为既然FP也被称为Monadic Programming,那么Free Monad应该是FP里最重要的数据结构,它的应用模式代表了主流FP,应该有个规范的具体使用方式。...在本次讨论中我们将会集中对Free Monad的应用模式进行示范体验。...就像是在for-loop里进行我们熟悉的行令编程:逐条指令编写。
Free Monad的出现恰恰解决我心中的疑问,更正了我对FP的偏见:Free Monad提供了一套在Monad 算法内(在 for-comprehension内)的行令编程(imperative programming...)方法,解决了FP的复杂语法,使Monadic编程更贴近传统编程模式的习惯和思维,程序意图更容易理解。...这时我们遇到了flatMap函数的方法糖for-comprehension,它可用让我们在一个for-loop里进行我们熟悉的行令式编程,就像下面这样: for { x <- getRecNo r...接触的多了我们就可以了解Monad的主要作用就是把一个算法,无论是一个值或者一个函数升格成Monad,这样我们就可以在Monad-for-comprehension里使用它们了。...看看scalaz里一些类型的Monad格式吧: case class State (run: S => (A,S)) case class Reader(run: A => B) case class
这就是State Monad的存在意义,想让状态维护变得更容易,同时不影响其它纯的部分 从实现角度看,State Monad是个函数,接受一个状态,返回一个值和新状态 s -> (a,s) -- 即 state...且看随机数的示例 随机数与State Monad 就场景而言,随机数需要维护状态(随机数种子),非常适合用State Monad来处理 具体的,之前在随机数的场景,通过给random函数换不同的随机数种子来生成随机数...(算上传入的mkStdGen 7),因为这个种子是最新的状态(其余中间状态都被丢掉了) 是的,Moand又简化了一个状态维护的通用场景,State Monad帮我们自动完成了中间状态的维护,让一切变得尽可能地简洁...五.Monad的魅力 Monad能够赋予计算一些额外的能力,比如: Writer Monad:能够把函数转换成带日志的版本,用来追踪执行过程,或者给数据变换添加额外的信息 Reader Monad:能够让一系列函数在一个可控的共享环境中协同工作...,比如从这个环境中读取参数,读取其它函数的结果等等 State Monad:能够自动维护状态,适用于需要维护状态的场景,比如生成一系列随机数 Error Monad:提供了一种错误处理机制,能够很方便地让运算更安全地进行
看看StateT,简单定义应该是这样的: case class StateT[F[_],S,A](run: S => F[(S,A)]) 我们可以把F类堆砌在State上。...好了,scalaz里有个ReaderWriterState这么个type class,就是一个Reader+Writer+State堆砌的Monad。...相信scalaz特别提供了这么个type class应该有它的用意。我的猜想是这个Monad是个功能比较完整的组合Monad。...在scalaz里是这样定义的:scalaz/ReaderWriterStateT.scala /** A monad transformer stack yielding `(R, S1) => F[(...我们看到IndexedReaderWriterStateT已经实现了很多IndexedStateT的运算方法如:eval,exec等。
领取专属 10元无门槛券
手把手带您无忧上云