什么是Monad?】的更多相关文章

Lifting Now, let's review map from another perspective. map :: (T -> R) -> [T] -> [R] accepts 2 parameters, a function f :: T -> R and a list list :: [T]. [T] is a generic type paramterized by T, it's not the same as T, but definitely shares s…
Atitit 理解Monad attilax总结 但函数式编程最大的一个问题是,函数是一个数学抽象,在现实世界中不存在,1 那既然这样就够用了,还要 Monad 干嘛?Monad 的作用在这里就体现出来了,它就是个加强的胶水函数1 但函数式编程最大的一个问题是,函数是一个数学抽象,在现实世界中不存在, 它必须被模拟出来.目前为止被广泛使用的计算机还是基于图灵机模型,计算机的寄存器.缓存.内存就是用来记录状态的.要真正懂得程序设计,必须知道没有状态的函数是如何在充满状态的计算机上实现的,所以还是绕…
我们不断地重申FP强调代码无副作用,这样才能实现编程纯代码.像通过键盘显示器进行交流.读写文件.数据库等这些IO操作都会产生副作用.那么我们是不是为了实现纯代码而放弃IO操作呢?没有IO的程序就是一段烧CPU的代码,没有任何意义,所以任何类型的程序都必须具备IO功能,而在FP模式中对IO操作有特别的控制方式:具体实现是通过把代码中产生副作用的部分抽离出来延后运算(在所有纯代码运算之后).scalaz的IO Monad就是处理副作用代码延后运算的一种数据结构.我先举个简单的例子来示范如何通过一种数…
在前面的讨论里我们提到自由数据结构就是产生某种类型的最简化结构,比如:free monoid, free monad, free category等等.我们也证明了List[A]是个free monoid.我们再看看free monad结构Free的定义:scalaz/Free.scala /** A free operational monad for some functor `S`. Binding is done using the heap instead of the stack,…
函数式编程模式强调纯代码(pure code),主要实现方式是使用不可变数据结构,目的是函数组合(composability)最终实现函数组件的重复使用.但是,如果我们在一个函数p内部使用了可变量(mutable variables),如果函数的输入参数e是纯代码,那么表达式p(e)同样是纯代码的,因为函数的调用者是无法接触到函数内部申明的这些可变量的.不过,这样的做法会造成函数的臃肿代码,因为在函数内部是无法实现函数组合的,无法重复使用函数组件,实际上又违背了FP的宗旨.Scalaz提供了专门…
中间插播了几篇scalaz数据类型,现在又要回到Monad专题.因为FP的特征就是Monad式编程(Monadic programming),所以必须充分理解认识Monad.熟练掌握Monad运用.曾经看到一段对Monad的描述:“Monadic for-comprehension就是一种嵌入式编程语言,由它的Monad提供它的语法”.但如果每一种Monad的for-comprehension都独立提供一套语法的话,这种编程语言就显得十分单调.功能简单了.那么既然是FP,我们应该可以通过函数组合…
scalaz还提供了个type class叫Validation.乍看起来跟\/没什么分别.实际上这个Validation是在\/的基础上增加了Applicative功能,就是实现了ap函数.通过Applicative实例就可以同时运算多个Validation并返回多条异常信息.所以,\/与Validation核心分别就在于Validation可以返回多条异常信息.Validation也是由两种状态组成:Success和Failure,分别与\/的left和right相对应.Failure可以返…
scala标准库提供了一个Either类型,它可以说是Option的升级版.与Option相同,Either也有两种状态:Left和Right,分别对应Option的None和Some,不同的是Left可以返回一个值.我们通常用这个值来表述异常信息.scalaz也提供了自己版本的Either,并用\/来分辨表示,以及两种状态-\/和\/-.我想scalaz特别提供\/是有原因的:\/不单是一种类型,它是一种type class.更重要的是\/是一种Monad,具备了函数组合能力(composib…
说道FP,我们马上会联想到Monad.我们说过Monad的代表函数flatMap可以把两个运算F[A],F[B]连续起来,这样就可以从程序的意义上形成一种串型的流程(workflow).更直白的讲法是:任何类型只要实现了flatMap就可以用for-comprehension, for{...}yield.在这个for{...}里我们可以好像OOP一样编写程序.这个for就是一种运算模式,它规范了在for{...}里指令的行为.我们正从OOP风格走入FP编程模式,希望有个最基本的FP编程模式使我…
我们经常提到函数式编程就是F[T].这个F可以被视为一种运算模式.我们是在F运算模式的壳子内对T进行计算.理论上来讲,函数式程序的运行状态也应该是在这个运算模式壳子内的,也是在F[]内更新的.那么我们就应该像函数式运算T值一样,也有一套函数式更新程序状态的方法.之前我们介绍了Writer Monad.Writer也是在F[]内维护Log的,可以说是一种状态维护方式.但Writer的Log是一种Monoid类型,只支持Semigroup的a|+|b操作,所以只能实现一种两段Log相加累积这种效果.…
在上一篇讨论里我们简单的介绍了一下Cake Pattern和Reader Monad是如何实现依赖注入的.主要还是从方法上示范了如何用Cake Pattern和Reader在编程过程中解析依赖和注入依赖.考虑到依赖注入模式在编程中的重要性和普遍性,觉着还需要再讨论的深入一些,使依赖注入模式在FP领域里能从理论走向实际.既然我们正在scalaz的介绍系列里,所以这篇我们就着重示范Reader Monad的依赖注入方法. 再说明一下依赖注入:我们说过在团队协作开发里能够实现软件模块的各自独立开发,原…
我们可以用Monad Reader来实现依赖注入(dependency injection DI or IOC)功能.Scala界中比较常用的不附加任何Framework的依赖注入方式可以说是Cake Pattern了.现在通过Monad Reader可以实现同样功能,两者对比优点各有千秋.所谓依赖注入是指在编程时使用了某个未知实现细节的对象,但依赖注入确保这个对象在这段程序运行时已经实例化.这种需求通常是在大型软件开发时对项目进行模块化分割后虽然模块之间互有依赖,但又可以同步开发.特别是在多人…
Monad Reader就是一种函数的组合.在scalaz里函数(function)本身就是Monad,自然也就是Functor和applicative.我们可以用Monadic方法进行函数组合: import scalaz._ import Scalaz._ object decompose { //两个测试函数 val f = (_: Int) + //> f : Int => Int = <function1> val g = (_: Int) * //> g : In…
通过前面的几篇讨论我们了解到F[T]就是FP中运算的表达形式(representation of computation).在这里F[]不仅仅是一种高阶类型,它还代表了一种运算协议(computation protocol)或者称为运算模型好点,如IO[T],Option[T].运算模型规范了运算值T的运算方式.而Monad是一种特殊的FP运算模型M[A],它是一种持续运算模式.通过flatMap作为链条把前后两个运算连接起来.多个flatMap同时作用可以形成一个程序运行链.我们可以在flat…
在前面的几篇讨论里我们初步对FP有了些少了解:FP嘛,不就是F[A]吗?也是,FP就是在F[]壳子(context)内对程序的状态进行更改,也就是在F壳子(context)内施用一些函数.再直白一点就是在F壳子内进行OOP惯用的行令编程(imperative programming).当然,既然是在壳子(context)内进行编程这种新的模式,那么总需要些新的函数施用方法吧.我们再次审视一下以前了解过的FP函数施用方法: // Functor : map[A,B] (F[A])(f: A =>…
前面提到了scalaz是个函数式编程(FP)工具库.它提供了许多新的数据类型.拓展的标准类型及完整的一套typeclass来支持scala语言的函数式编程模式.我们知道:对于任何类型,我们只需要实现这个类型的typeclass实例就可以在对这个类型施用所对应typeclass提供的所有组件函数了(combinator).突然之间我们的焦点好像都放在了如何获取typeclass实例上了,从而忽略了考虑为什么要使用这些typeclass及使用什么样的typeclass这些问题了.所以可能有人会问我:…
Monad typeclass不是一种类型,而是一种程序设计模式(design pattern),是泛函编程中最重要的编程概念,因而很多行内人把FP又称为Monadic Programming.这其中透露的Monad重要性则不言而喻.Scalaz是通过Monad typeclass为数据运算的程序提供了一套规范的编程方式,如常见的for-comprehension.而不同类型的Monad实例则会支持不同的程序运算行为,如:Option Monad在运算中如果遇到None值则会中途退出:State…
泛函编程的核心模式就是函数组合(compositionality).实现函数组合的必要条件之一就是参与组合的各方程序都必须是纯代码的(pure code).所谓纯代码就是程序中的所有表达式都必须是Referentially Transparent(RT,等量可替换的),它的意思是:在一段程序p中,所有的表达式e都可以用e的运算结果替代而不影响到p的运算结果,那么e就是RT等量可替换的,也就是说程序p是由纯代码组成的.但如果程序p中包含了一些变量,这些变量的状态就会影响到程序中e的运算结果,那么p…
由于泛函编程非常重视函数组合(function composition),任何带有副作用(side effect)的函数都无法实现函数组合,所以必须把包含外界影响(effectful)副作用不纯代码(impure code)函数中的纯代码部分(pure code)抽离出来形成独立的另一个纯函数.我们通过代码抽离把不纯代码逐步抽离向外推并在程序里形成一个纯代码核心(pure core).这样我们就可以顺利地在这个纯代码核心中实现函数组合.IO Monad就是泛函编程处理副作用代码的一种手段.我们先…
在上节我们介绍了Free Monad的基本情况.可以说Free Monad又是一个以数据结构替换程序堆栈的实例.实际上Free Monad的功能绝对不止如此,以heap换stack必须成为Free Monad的运算模式,这样我们才可以放心的使用Free Monad所产生的Monadic编程语言了.前面我们介绍了Trampoline的运算模式可以有效解决堆栈溢出问题,而上节的Free Monad介绍里还没有把Free Monad与Trampoline运算模式挂上钩.我们先考虑一下如何在Free M…
在上节我们介绍了Trampoline.它主要是为了解决堆栈溢出(StackOverflow)错误而设计的.Trampoline类型是一种数据结构,它的设计思路是以heap换stack:对应传统递归算法运行时在堆栈上寄存程序状态,用Trampoline进行递归算法时程序状态是保存在Trampoline的数据结构里的.数据结构是在heap上的,所以可以实现以heap换stack的效果.这种以数据结构代替函数调用来解决问题的方式又为泛函编程提供了更广阔的发展空间. 我们知道,任何涉及IO的运算都会面临…
经过了一段时间的泛函编程讨论,始终没能实实在在的明确到底泛函编程有什么区别和特点:我是指在现实编程的情况下所谓的泛函编程到底如何特别.我们已经习惯了传统的行令式编程(imperative programming),总是先入为主的认为软件编程就是一行接着一行的更改某些变量状态指令:明刀明枪,字里行间目的和方式都很明确.我们就以一步步更改程序状态的方式,一行一行的拼凑指令:这就是典型的行令式编程了. 泛函编程,顾名思义,就是用一个个函数来编程.讲的再深入点就是通过函数组合来更改程序状态.什么意思?为…
经过了一段时间的学习,我们了解了一系列泛函数据类型.我们知道,在所有编程语言中,数据类型是支持软件编程的基础.同样,泛函数据类型Foldable,Monoid,Functor,Applicative,Traversable,Monad也是我们将来进入实际泛函编程的必需.在前面对这些数据类型的探讨中我们发现: 1.Monoid的主要用途是在进行折叠(Foldable)算法时对可折叠结构内元素进行函数施用(function application). 2.Functor可以对任何高阶数据类型F[_]…
前面我们讨论了Applicative.Applicative 就是某种Functor,因为我们可以用map2来实现map,所以Applicative可以map,就是Functor,叫做Applicative Functor.我们又说所有Monad都是Applicative,因为我们可以用flatMap来实现map2,但不是所有数据类型的flatMap都可以用map2实现,所以反之不是所有Applicative都是Monad.Applicative注重于各种类型的函数施用,也就是map.包括普通函…
上两期我们讨论了Monad.我们说Monad是个最有概括性(抽象性)的泛函数据类型,它可以覆盖绝大多数数据类型.任何数据类型只要能实现flatMap+unit这组Monad最基本组件函数就可以变成Monad实例,就可以使用Monad组件库像for-comprehension这样特殊的.Monad具备的泛函式数据结构内部的按序计算运行流程.针对不同的数据类型,flatMap+unit组件实现方式会有所不同,这是因为flatMap+unit代表着承载数据类型特别的计算行为.之前我们尝试了List,O…
monad本意是单子.在haskell中,第一个接触的基本都是IO action,通过把IO动作包装起来我们能很方便的与现实世界进行数据交换.但其实monad的用途不止如此,monad还能讲一系列操作进行序列化,而这一点在通常编程中是非常需要的.而在haskell中,类似的事情则是通过递归来完成了平时需要序列化的工作.但其实haskell中也有能进行顺序操作的方法,那就是monad.一个类似于monad的定义基本是这个样子的. class Computation c where success…
看到一遍好文章,与我的想法如出一辙,先转为敬.首先说说我对Monad和promise的理解: Monad的这种抽象方式是为了简化程序中不确定状态的判断而提出的,能够让程序员从更高的层次顺序描述程序逻辑的每一个动作,而不必关注每一个动作是否会出现异常,也不必关注第一个动作内是否需要逻辑判断,是否要跳转.haskell趣学指南我翻了好几遍,终于对Monad这个概念有了一点认识,这个抽象是伟大的,它极大提高了程序的可读性,同时降低了开发难度.这里还要推荐一下haskell这门语言,Monad的概念就是…
在上一节我们介绍了Monad.我们知道Monad是一个高度概括的抽象模型.好像创造Monad的目的是为了抽取各种数据类型的共性组件函数汇集成一套组件库从而避免重复编码.这些能对什么是Monad提供一个明确的答案吗?我们先从上节设计的Monad组件库中的一些基本函数来加深一点对Monad的了解: trait Monad[M[_]] extends Functor[M] { def unit[A](a: A): M[A] def flatMap[A,B](ma: M[A])(f: A => M[B]…
简单来说:Monad就是泛函编程中最概括通用的数据模型(高阶数据类型).它不但涵盖了所有基础类型(primitive types)的泛函行为及操作,而且任何高阶类或者自定义类一旦具备Monad特性就可以与任何类型的Monad实例一样在泛函编程中共同提供一套通用的泛函编程方式.所以有人把泛函编程视作Monadic Programming也不为过之.那么,具体什么是Monad呢? 在前面我们讨论过Monoid,我们说过它是一个特殊的范畴(Category),所有数据类型的Monoid实例都共同拥有一…
这是观看Cousera上的课程<Principles of Reactive Programming>中week1里的Monad一节所做的笔记. What is a Monad? What is a Monad? A monad is a parametric type M[T] with two operations, flatMap and unit, that have to satisfy some laws. 这里是说Monad是一类特殊的类型,它有两个方法, flatMap和uni…