![](https://img-blog.csdnimg.cn/20201014180756754.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
泛函编程(Functional Programming)
文章平均质量分 78
TIGER_XC
一个Scala童鞋
展开
-
Scalaz(11)- Monad:你存在的意义
前面提到了scalaz是个函数式编程(FP)工具库。它提供了许多新的数据类型、拓展的标准类型及完整的一套typeclass来支持scala语言的函数式编程模式。我们知道:对于任何类型,我们只需要实现这个类型的typeclass实例就可以在对这个类型施用所对应typeclass提供的所有组件函数了(combinator)。突然之间我们的焦点好像都放在了如何获取typeclass实例上了,从而忽略了详原创 2015-10-28 13:46:16 · 645 阅读 · 0 评论 -
Scalaz(37)- Free :实践-DB Transaction free style
我一直在不断的提示大家:FP就是Monadic Programming,是一种特殊的编程风格。在我们熟悉的数据库编程领域能不能实现FP风格呢?我们先设计一些示范例子来分析一下惯用的数据库编程过程:import scalaz._import Scalaz._import scala.language.higherKindsimport scala.language.implicitConv原创 2016-03-30 12:26:01 · 774 阅读 · 0 评论 -
Scalaz(33)- Free :算式-Monadic Programming
在任何模式的编程过程中都无法避免副作用的产生。我们可以用F[A]这种类型模拟FP的运算指令:A是可能产生副作用的运算,F[_]是个代数数据类型ADT(Algebraic Data Type),可以实现函数组合(functional composition),我们可以不用理会A,先用F[_]来组合形成描述功能的抽象程序AST(Abstract Syntax Tree),对A的运算可以分开另一个过程去实现,而且可以有多种的运算实现方式,这样就达到了算式AST(Monadic Programming)、算法(In原创 2016-03-19 15:46:10 · 450 阅读 · 0 评论 -
Scalaz(27)- Inference & Unapply :类型的推导和匹配
经过一段时间的学习演练,用scala进行函数式编程的过程对我来说就好像是着重如何将函数的款式对齐以及如和正确匹配类型。真正是一种全新的体验,有点太偏重学术型了。原创 2016-02-23 21:04:20 · 620 阅读 · 0 评论 -
Scalaz(29)- Free :Coyoneda - Functor for free
很多时候我们会遇到一些高阶类型F[_],但又无法实现它的map函数,也就是虽然形似但F不可能成为Functor。看看下面的例子:trait Interact[A]case class Ask(prompt: String) extends Interact[String]case class Tell(msg: String) extends Interact[Unit]In原创 2016-03-11 07:55:27 · 645 阅读 · 0 评论 -
Scalaz(30)- Free :Natural Tranformation ~> - map higher kinded types for free
当我们需要定义一些对应高阶类型进行相互类型转换的操作函数时,我们发现scala语言并不提供能定义这种函数的支持。举例来说:如果我们希望定义一个函数把对于任何T值的Option[T]转换成List[T]的话,我们可能这样定义:def toList[T](opt: Option[T]): List[T] = opt.toList原创 2016-03-11 14:47:11 · 643 阅读 · 0 评论 -
Scalaz(34)- Free :算法-Interpretation
我们说过自由数据结构(free structures)是表达数据类型的最简单结构。List[A]是个数据结构,它是生成A类型Monoid的最简单结构,因为我们可以用List的状态cons和Nil来分别代表Monoid的append和zero。Free[S,A]是个代表Monad的最简单数据结构,它可以把任何Functor S升格成Monad。Free的两个结构Suspend,Return分别代表了原创 2016-03-23 09:49:20 · 519 阅读 · 0 评论 -
Scalaz(31)- Free :自由数据结构-算式和算法的关注分离
我们可以通过自由数据结构(Free Structure)实现对程序的算式和算法分别考虑。算式(Abstract Syntax Tree, AST)即运算表达式,是对程序目的的描述。算法则是程序的具体运算方式(Interpreter),它赋予了算式意义。下面我们先简单解释yi x原创 2016-03-12 21:30:34 · 515 阅读 · 0 评论 -
Scalaz(35)- Free :运算-Trampoline,say NO to StackOverflowError
在前面几次讨论中我们介绍了Free是个产生Monad的最基本结构。它的原理是把一段程序(AST)一连串的运算指令(ADT)转化成数据结构存放在内存里,这个过程是个独立的功能描述。然后在独立的运算过程中Interpreter会遍历(traverse)AST结构,读取结构里的运算指令,具体运行指令。这里的重点是把一连串运算结构化(reify)延迟运行,具体实现方式是把Monad的连续运算方法flatM原创 2016-03-25 21:18:43 · 604 阅读 · 0 评论 -
Scalaz(38)- Free :Coproduct-Monadic语句组合
很多函数式编程爱好者都把FP称为Monadic Programming,意思是用Monad进行编程。我想FP作为一种比较成熟的编程模式,应该有一套比较规范的操作模式吧。因为Free能把任何F[A]升格成Monad,所以Free的算式(AST)、算法(Interpreter)关注分离(separation of concern)应用模式应该可以成为一种规范的FP编程模式。我们在前面的几篇讨论中都涉及原创 2016-04-12 11:14:17 · 2584 阅读 · 0 评论 -
Scalaz(36)- Free :实践-Free In Action - 实用体验
在上面几期讨论中我们连续介绍了Free Monad。因为FP是纯函数编程,也既是纯函数的组合集成,要求把纯代码和副作用代码可以分离开来。Free Monad的程序描述(AST)和程序实现(Interpretation)关注分离(separation of concern)模式恰恰能满足FP要求。我们可以用一些代数数据类型(ADT Algebraic Data Type)来模拟功能,再把这些ADT组原创 2016-03-28 11:46:36 · 532 阅读 · 0 评论 -
Scalaz(32)- Free :lift - 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`. Bi原创 2016-03-18 08:12:37 · 592 阅读 · 0 评论 -
Scalaz(23)- 泛函数据结构: Zipper-游标定位
外面沙尘滚滚一直向北去了,意识到年关到了,码农们都回乡过年去了,而我却留在这里玩弄“拉链”。不要想歪了,我说的不是裤裆拉链而是scalaz Zipper,一种泛函数据结构游标(cursor)。在函数式编程模式里的集合通常是不可变的(immutable collection),我们会发现在FP编程过程中处理不可变集合(immutable collection)数据的方式好像总是缺些什么,比如在集合里原创 2016-01-06 21:28:58 · 537 阅读 · 0 评论 -
Scalaz(10)- Monad:就是一种函数式编程模式-a design pattern
Monad typeclass不是一种类型,而是一种程序设计模式(design pattern),是泛函编程中最重要的编程方式,因而很多行内人把FP又称为Monadic Programming。这其中代表的重要性不言而喻。Scalaz是通过Monad typeclass为数据运算的程序提供了一套规范的编程方式,如著名的for-comprehension。而不同类型的Monad实例则会支持不同的程序原创 2015-10-20 06:26:58 · 936 阅读 · 0 评论 -
Scalaz(13)- Monad:Writer - some kind of logger
在上一篇讨论中我们再次介绍了Monad,并重新认识了flatMap可以形成运算链接实现持续计算。我们同时介绍了如何在flatMap函数实现过程中增加附加作用。上一节我们用了个Logger例子来示范如何在flatMap把logging功能加入到Monad实例。本篇讨论我们首先对上篇的Logger例子进行一些概括,设计一个新的Logger结构:case class Logger[LOG, A](l原创 2015-11-20 10:01:20 · 575 阅读 · 0 评论 -
Scalaz(21)-类型例证:Liskov and Leibniz - type evidence
Leskov,Leibniz,别扭的名字,是什么地干活?碰巧从scalaz源代码里发现了这么个东西:scalaz/BindSyntax.scala/** Wraps a value `self` and provides methods related to `Bind` */final class BindOps[F[_],A] private[syntax](val self: F[A]原创 2015-12-29 08:55:33 · 515 阅读 · 0 评论 -
Scalaz(14)- Monad:函数组合-Kleisli to Reader
Monad Reader就是一种函数的组合。在scalaz里函数(function)本身就是Monad,自然也就是Functor和applicative。我们可以用Monadic方法来组合函数:import scalaz._import Scalaz._object decompose {//两个测试函数val f = (_: Int) + 3原创 2015-11-25 21:12:00 · 657 阅读 · 0 评论 -
Scalaz(15)- Monad:依赖注入-Reader besides Cake
我们可以用Monad Reader来实现依赖注入(dependency injection DI or IOC)功能。Scala界中比较常用的不附加任何Framework的依赖注入方式可以说是Cake Pattern了。现在通过Monad Reader可以实现同样功能,两者对比优点各有千秋。所谓依赖注入是指在编程时使用了某个未知实现细节的对象,但依赖注入确保这个对象在这段程序运行时已经实例化。这种原创 2015-11-27 19:00:09 · 606 阅读 · 0 评论 -
Scalaz(18)- Monad: ReaderWriterState-可以是一种简单的编程语言
import scalaz._, Scalaz._object RWSExample { case class Config(port: Int) def log[R, S](msg: String): RWS[R, List[String], S, Unit] = ReaderWriterState { case (r, s) => (msg.format(r,原创 2015-12-15 17:49:37 · 627 阅读 · 0 评论 -
Scalaz(19)- Monad: \/ - Monad 版本的 Either
scala标准库提供了一个Either类型,它可以说是Option的升级版。与Option相同,Either也有两种状态:Left和Right,分别对应Option的None和Some,不同的是Left可以返回一个值。我们通常用这个值来表述异常信息。scalaz也提供了自己版本的Either,并用\/来分辨表示,以及两种状态-\/和\/-。我想scalaz特别提供\/是有原因的:\/不单是一种类型原创 2015-12-17 13:22:25 · 600 阅读 · 0 评论 -
Scalaz(20)-Monad: Validation-Applicative版本的Either
scalaz还提供了个type class叫Validation。乍看起来跟\/没什么分别。实际上这个Validation是在\/的基础上增加了Applicative功能,就是实现了ap函数。通过Applicative实例就可以同时运算多个Validation并返回多条异常信息。所以,\/与Validation核心分别就在于Validation可以返回多条异常信息。Validation也是由两种状原创 2015-12-17 18:14:20 · 881 阅读 · 0 评论 -
Scalaz(25)- Monad: Monad Transformer-叠加Monad效果
中间插播了几篇scalaz数据类型,现在又要回到Monad专题。因为FP的特征就是Monad式编程(Monadic programming),所以必须充分理解认识Monad、熟练掌握Monad运用。曾经看到一段对Monad的描述:Monadic for-comprehension就是一种嵌入式编程语言,由它的Monad提供它的语法。但如果每一种Monad的for-comprehension都独立提原创 2016-01-20 08:43:40 · 932 阅读 · 0 评论 -
Scalaz(24)- 泛函数据结构: Tree-数据游览及维护
上节我们讨论了Zipper-串形不可变集合(immutable sequential collection)游标,在串形集合中左右游走及元素维护操作。这篇我们谈谈Tree。在电子商务应用中对于xml,json等格式文件的处理要求非常之普遍,scalaz提供了Tree数据类型及相关的游览及操作函数能更方便高效的处理xml,json文件及系统目录这些树形结构表现形式数据的相关编程。scalaz Tre原创 2016-01-08 08:28:04 · 625 阅读 · 0 评论 -
Scalaz(40)- Free :versioned up,再回顾
在上一篇讨论里我在设计示范例子时遇到了一些麻烦。由于Free Monad可能是一种主流的FP编程规范,所以在进入实质编程之前必须把所有东西都搞清楚。前面遇到的问题主要与scalaz Free的FreeC类型有关系。这个类型主要是针对一些非Functor的F[A]特别设计的。FreeC是Coyoneda[F,A]的Free Monad类型,任何F[A]都可以被转换成Coyoneda[F,A],而Co原创 2016-04-26 12:29:16 · 1117 阅读 · 0 评论 -
Scalaz(41)- Free :IO Monad-Free特定版本的FP语法
我们不断在重申FP强调代码无副作用,这样才能实现纯代码。像通过键盘显示器进行交流、读写文件、数据库等这些IO操作都会产生副作用。那么我们是不是为了实现纯代码而放弃IO操作呢?没有IO的程序就是一段烧CPU的代码,没有任何意义,所以任何类型的程序都必须具备IO功能,而在FP模式中对IO操作有特别的控制方式:具体实现是通过把代码中产生副作用的部分抽离出来延后运算(在所有纯代码运算之后)。scalaz的原创 2016-05-10 18:57:48 · 957 阅读 · 0 评论 -
Scalaz(55)- scalaz-stream: fs2-基础介绍,fs2 stream transformation
fs2是scalaz-stream的最新版本,沿用了scalaz-stream被动式(pull model)数据流原理但采用了全新的实现方法。fs2比较scalaz-stream而言具备了:更精简的基础组件(combinator)、更安全的类型、资源使用(type safe, resource safety)、更高的运算效率。由于fs2基本沿用了scalaz-stream的原理,所以我们会在下面的原创 2016-08-24 10:04:42 · 625 阅读 · 0 评论 -
Scalaz(53)- scalaz-stream: 程序运算器-application scenario
从上面多篇的讨论中我们了解到scalaz-stream代表一串连续无穷的数据。对这个数据流的处理过程就是一个状态机器(state machine)的状态转变过程。这种模式与我们通常遇到的程序流程很相似:通过程序状态的变化来推进程序进展。传统OOP式编程可能是通过一些全局变量来记录当前程序状态,而FP则是通过函数组合来实现状态转变的。这个FP模式讲起来有些模糊和抽象,但实际上通过我们前面长时间对FP原创 2016-08-12 10:02:50 · 567 阅读 · 0 评论 -
Scalaz(56)- scalaz-stream: fs2-安全运算,fs2 resource safety
fs2在处理异常及资源使用安全方面也有比较大的改善。fs2 Stream可以有几种方式自行引发异常:直接以函数式方式用fail来引发异常、在纯代码里隐式引发异常或者在运算中引发异常,举例如下:/函数式val err = Stream(1,2,3) ++ Stream.fail(new Exception("oh,no...")) //> err : fs2.Stream[Nothi原创 2016-08-25 10:50:46 · 630 阅读 · 0 评论 -
Cats(1)- 从Free开始,Free cats
cats是scala的一个新的函数式编程工具库,其设计原理基本继承了scalaz:大家都是haskell typeclass的scala版实现。当然,cats在scalaz的基础上在实现细节、库组织结构和调用方式上有一些变化,所以对用户来说:cats的基础数据类型、数据结构在功能上与scalaz是大致相同的,可能有一些语法上的变化。与scalaz著名的抽象语法表现形式相比,cats的语法可能更形象原创 2016-09-06 10:02:35 · 1306 阅读 · 0 评论 -
FunDA(0)- Functional Data Access accessible to all
大数据、多核CPU驱动了函数式编程模式的兴起。因为函数式编程更适合多线程、复杂、安全的大型软件编程。但是,对许多有应用软件开发经验的编程者来说,函数式编程模式是一种全新的、甚至抽象的概念,可能需要很长时间的学习、积累才能完全掌握和适应。对一些不算scala编程专家的人来说,如何用他们习惯的方式来使用现成的函数式软件如Slick,Spark等就变得是件很迫切的事情了。设计FunDA的想法就是希望那些原创 2016-12-20 09:56:29 · 571 阅读 · 0 评论 -
FunDA(8)- Static Source:保证资源使用安全 - Resource Safety
我们在前面用了许多章节来讨论如何把数据从后台数据库中搬到内存,然后进行逐行操作运算。我们选定的解决方案是把后台数据转换成内存中的数据流。无论在打开数据库表或从数据库读取数据等环节都涉及到对数据库表这项资源的安全使用:我们最起码要保证在完成使用或者使用中途出现错误异常退出时能释放占用的资源。谈到资源使用安全,不得不想到函数式编程通用的那个bracket函数,fs2同样提供了这个函数:def br原创 2017-02-10 08:36:36 · 468 阅读 · 0 评论 -
FunDA(11)- 数据库操作的并行运算:Parallel data processing
FunDA最重要的设计目标之一就是能够实现数据库操作的并行运算。我们先重温一下fs2是如何实现并行运算的。我们用interleave、merge、either这几种方式来同时处理两个Stream里的元素。interleave保留了固定的交叉排列顺序,而merge和either则会产生不特定顺序,这个现象可以从下面的例子里看到:implicit val strategy = Strategy.f原创 2017-02-20 14:37:10 · 777 阅读 · 0 评论 -
FunDA(12)- 示范:强类型数据源 - strong typed data sources
FunDA设计的主要目的是解决FRM(Functional Relation Mapping)如Slick这样的批次型操作工具库数据源行间游动操作的缺失问题。FRM产生的结果集就是一种静态集合,缺乏动态更新操作方式。FunDA提出的解决方案是把FRM产生的静态集合转变成动态流(stream),流内元素代表数据行(data row),一个完整的数据流代表一连串的数据行。用户可以利用数据流和FunDA原创 2017-03-01 20:36:47 · 786 阅读 · 0 评论 -
FunDA(9)- Stream Source:reactive data streams
上篇我们讨论了静态数据源(Static Source, snapshot)。这种方式只能在预知数据规模有限的情况下使用,也可以说是不安全的资源使用方式。Slick3.x已经增加了支持Reactive-Streams功能,可以通过Reactive-Streams API来实现有限内存空间内的无限规模数据读取,这正符合了FunDA的设计理念:高效、便捷、安全的后台数据处理工具库。我们在前面几篇讨论里介原创 2017-02-14 11:33:35 · 443 阅读 · 0 评论 -
FunDA(10)- 用户功能函数模式:User Function Model
前面我们提过:FunDA就像一个管道(PipeLine)。管道内流动着一串数据(Data)或者运算指令(Action)。管道的源头就是能产生纯数据的数据源(Source),跟着在管道的中间会有一些节点(WorkNode),我们可以在这些节点施用(apply)用户提供的功能函数(Task)。用户功能函数可以截取并使用管道中流动的数据或者指令,然后利用一种水龙头开关机制(Valve)来影响流动元素:可原创 2017-02-16 08:21:47 · 415 阅读 · 0 评论 -
Scalaz(59)- scalaz-stream: fs2-程序并行运算,fs2 running effects in parallel
scalaz-stream-fs2是一种函数式的数据流编程工具。fs2的类型款式是:Stream[F[_],O],F[_]代表一种运算模式,O代表Stream数据元素的类型。实际上F就是一种延迟运算机制:F中间包含的类型如F[A]的A是一个可能会产生副作用的不纯代码(impure code)的运算结果类型,我们必须用F对A运算的延迟机制才能实现编程过程中的函数组合(compositionality原创 2016-08-31 11:34:33 · 1078 阅读 · 0 评论 -
Scalaz(58)- scalaz-stream: fs2-并行运算示范,fs2 parallel processing
从表面上来看,Stream代表一连串无穷数据元素。一连串的意思是元素有固定的排列顺序,所以对元素的运算也必须按照顺序来:完成了前面的运算再跟着进行下一个元素的运算。这样来看,Stream应该不是很好的并行运算工具。但是,fs2所支持的并行运算方式是以完整的Steam为运算单位的:支持多个Stream同时进行运算,如merge。所以fs2使Stream的并行运算成为了可能。原创 2016-08-30 07:59:40 · 1074 阅读 · 0 评论 -
Scalaz(39)- Free :a real monadic program
一直感觉FP比较虚,可能太多学术性的东西。不知道如何把这些数学理论在背后支持的一套全新数据类型和数据结构在现实开发中加以使用。直到Free Monad,才真正感觉能用FP方式进行编程了。这次我想跟大家讨论一下用Free Monad来编写一个真正能运行的完整应用程序。当然,这个程序必须具备FP特性,比如函数组合(function composition),纯代码(pure code),延迟副作用(d原创 2016-04-18 11:17:21 · 3099 阅读 · 1 评论 -
Scalaz(43)- 总结 :FP就是实用的编程模式
完成了对Free Monad的学习了解后,心头豁然开朗,存在心里对FP的疑虑也一扫而光。之前也抱着跟大多数人一样的主观概念,认为FP只适合学术性探讨、缺乏实际应用、运行效率低,很难发展成现实的软件开发模式。Free Monad的出现恰恰解决我心中的疑问,更正了我对FP的偏见:Free Monad提供了一套在Monad 算法内(在 for-comprehension内)的行令编程(imperativ原创 2016-06-04 13:30:56 · 1333 阅读 · 0 评论 -
Scalaz(44)- concurrency :scalaz Future,尚不完整的多线程类型
scala已经配备了自身的Future类。我们先举些例子来了解scala Future的具体操作:原创 2016-06-15 11:37:52 · 512 阅读 · 0 评论