在scalaz里,Functor就是一个普通的typeclass,具备map over特性。我的理解中,Functor的主要用途是在FP过程中更新包嵌在容器(高阶类)F[T]中元素T值。...scalaz提供了Functor typeclass不但使用户能map over自定义的高阶类型F[T],并且用户通过提供自定义类型的Functor实例就可以免费使用scalaz Functor typeclass...scalaz中Functor的trait是这样定义的:scalaz/Functor.scala 1 trait Functor[F[_]] extends InvariantFunctor[F] { self...针对我们自定义的类型,我们只要实现map函数就可以得到这个类型的Functor实例。一旦实现了这个类型的Functor实例,我们就可以使用以上scalaz提供的所有Functor组件函数了。...类型的Functor实例我们就能免费使用所有的注入方法: scalaz提供了Function1的Functor实例。
在前几篇关于Functor和Applilcative typeclass的讨论中我们自定义了一个类型Configure,Configure类型的定义是这样的: 1 case class Configure...我们只要证明Configure类型的实例能遵循它所代表的typeclass操作定律就行了。Scalaz为大部分typeclass提供了测试程序(scalacheck properties)。...在scalaz/Functor.scala文件中定义了这几条定律: 1 trait FunctorLaw extends InvariantFunctorLaw { 2 /** The identity...我们在下面试着对那个Configure类型进行Functor实例和Applicative实例的测试: 1 import scalaz._ 2 import Scalaz._ 3 import shapeless...外还必须定义Configure类型的Equal实例以及任意测试数据产生器(test data generator)configArbi[A]。
IndexedStateT就是MonadState的子类,所以通过IndexedStateT的实例来施用状态运算函数是没用什么问题的。...我只能无奈的告诉你:其实什么也没干,可以在即时编译器里看看: import Scalaz._ import scala.language.higherKinds def f[M[_]: Functor...我想它只是示范了如何取得一些type class的StateT实例吧。我们知道,获取了一些type class的StateT实例后就可以对StateT施用这些type class的方法函数了。...下面是如何获取这些实例以及简单的type class函数引用: 1 //Functor实例 2 val fs = Functor[({type l[a] = StateT[List, Int, a...还是介绍些实际点的例子吧。最好能把在现实应用中如何选择使用State的思路过程示范一下。
突然之间我们的焦点好像都放在了如何获取typeclass实例上了,从而忽略了考虑为什么要使用这些typeclass及使用什么样的typeclass这些问题了。...我们就围绕scalaz提供的我们都熟悉的typeclass Functor, Applicative, Monad来分析说明吧,因为我们在前面对它们都进行了讨论介绍,为了与scalaz提供的众多其它typeclass...Scalaz通过Functor, Applicative, Monad提供了三种基本的函数施用方式,它们都是针对F[T]里的T值: 1 // Functor : map[T,U] (F[T...它们都因为基于不同类型的实例而表现不同的运算行为。Functor, Applicative, Monad的特质则由它们的实例中map, ap, flatMap这三个驱动函数的具体实现方式所决定。...程序没有区别。
虽然在sayHi函数内部并没有引用这个隐式参数isthere,但这个例子可以说明编译器进行类型推断的原理。...在Scalaz中还有些更复杂的引用例子如:scalaz/BindSyntax.scala def join[B](implicit ev: A 中不但限定了类型的正确性,而且还进行了些类型关系的推导。理论上我们可以用依赖类型(dependent type)来描述类型参数之间的关系,推导结果类型最终确定代码中类型的正确无误。...Scalaz的unapply就利用了依赖类型的原理,然后通过隐式参数(implicit parameter)证明某些类型实例的存在来判断输入参数类型正确性的。...那么在Unapply里有没有适合的款式呢?
很多时候我们会遇到一些高阶类型F[_],但又无法实现它的map函数,也就是虽然形似但F不可能成为Functor。...也就是说我们需要把Interact当做Functor才能构建一个基于Interact的Free Monad。...Scalaz里的Coyoneda与任何F[_]类型成同构(互等),而Coyoneda是个Functor,这样我们可以用Coyoneda来替代F。...我们来看看Coyoneda的定义:scalaz/Coyoneda.scala sealed abstract class Coyoneda[F[_], A] { coyo => /** The pivot...上面例子中的Interact也可以用Coyoneda替代: 1 trait Interact[A] 2 case class Ask(prompt: String) extends Interact[String
我们在前面的讨论中不断提到FP模式的操作一般都在管道里进行的,因为FP的变量表达形式是这样的:F[A],即变量A是包嵌在F结构里的。...与其它scalaz typeclass使用方式一样,我们只需要实现了针对自定义类型的Applicative实例就可以使用这些方法了。...注意Apply又继承了Functor,所以我们还需要实现map,一旦实现了Applicative实例就能同时获取了Functor实例。...,我们必须先获取Configure的Functor实例。...最典型的例子是Option类型在FP中结合OOP函数库的使用。
而不同类型的Monad实例则会支持不同的程序运算行为,如:Option Monad在运算中如果遇到None值则会中途退出;State Monad会确保状态值会伴随着程序运行流程直到终结;List Monad...所以Monad同时又是Applicative和Functor,因为Monad实现了map和ap函数。一个Monad实例可以调用所有Applicative和Functor提供的组件函数。...),没有副作用(no side-effect)。...而且程序运算行为只会受一种类型的特性所控制。如上面所叙,Monad实例的类型控制Monadic程序的运算行为。每一种Monad实例的程序可以有不同的运算方式。...在本篇讨论中我们介绍了Monad实际上是一种编程模式,并且示范了简单的for loop内部流程运算。在下面的一系列讨论中我们将会了解更多类型的Monad,以及Monad如何能成为功能完善的编程语言。
我们再看看free monad结构Free的定义:scalaz/Free.scala /** A free operational monad for some functor `S`....Suspend(a: S[Free[S,A]])代表把下一个运算存放在结构中。...注意,Suspend(a: S[Free[S,A]])是个递归类型,S必须是个Functor,但不是任何Functor,而是map over Free[S,A]的Functor,也就是运算另一个Free...简单来说Free是一个把Functor S[_]升格成Monad的产生器。我们可以用Free.liftF函数来把任何一个Functor升格成Monad。...但是又想了想,一个是Functor的Interact又是怎样的呢?
实际上造成FreeC类型麻烦的根本是Free[S[_],A]类型其中一个实例case class Suspend[S[_],A](s: S[Free[S,A]]),这个实例必须用monad的join来运算...另一个原因可能是scalaz借鉴了haskell的实现方式。无论如何,为了解决我们遇到的问题,必须想办法绕过S必须是Functor这个门槛。...在查找相关资料时发现Cats的Free里根本没有FreeC这个类型。当然也就没有liftFC这么个升格函数了。...正想着如何用Cats的Free来替代scalaz Free时才发现最新scalaz版本722(前面我一直使用是scalaz v7.1)里面的Free结构定义竟然已经升级了,看来许多其他的scalaz使用者都应该遇到了相同的麻烦...在上次的示范例子中遗留下来最需要解决的问题是如何实现多于两种ADT联合语句集的编程,这还是由于联合语句集G[_]是后置的原因。
先了解一下函数组合:Functor是可以组合的,我们可以把fa和fb组合成一个更复杂的Functor fab,我们来验证一下: def composeFunctor[M[_],N[_]](fa: Functor...在它的for-comprehension里的运算结果类型是ReaderWriterState一种,所以没有stair-stepping忧虑。但我们必须先创建一个新的类型(不是通过函数组合的新类型)。...值得注意的是,Monad Transformer 类型的构建是由内向外反向的。比如上面的例子中OptionT是个Monad Transformer,它的类型款式是OptionT[M[_],A]。...,应该是没有任何意义的一个类型。...的确,用Monad Transformer组合Monad后可以实现成员Monad的效果叠加。 不过,在实际应用中两层以上的Monad组合还是比较普遍的。
在scalaz的学习过程中,我们了解到所谓函数式编程就是monadic Programming:即用monad这样的数据类型来构建程序。...同时,我们可以在使用cats.Free的过程中对cats的其它数据类型进行补充了解。...的讨论中并没能详尽地分析在什么情况下S[_]必须是个Functor。...Interact Functor实例的map函数。...既然cats.Free对F[A]没有设置Functor门槛,那么我们应该尽量避免使用Functor。 得出对ADT类型要求结论后,我们接着示范cats的Free编程。
在上面几期讨论中我们连续介绍了Free Monad。因为FP是纯函数编程,也既是纯函数的组合集成,要求把纯代码和副作用代码可以分离开来。...AST既是对程序功能的描述,它的组成过程也就是Monadic Programming了。在另外一个过程中,我们可以按需要去实现各种Interpreter,从而达到实际运算的目的。...在本次讨论中我们将会集中对Free Monad的应用模式进行示范体验。...我们在这次示范中模拟一个针对键值存储(Key Value Store)的操作例子: 1、ADT设计 1 sealed trait KVS[+Next] 2 object KVS { 3 case class...2、获取Functor实例 1 implicit val kvsFunctor = new Functor[KVS] { 2 def map[A,B](kvs: KVS[A])(f: A
在前面的讨论中我们介绍过:我们可以把任何F[A]升格成Monad,而Monad具备最完善的函数组合性能,特别是它支持for-comprehension这种表达方式。...我们可以map over Next类型获取Quiz的Functor实例: 1 implicit object QFunctor extends Functor[Quiz] { 2 def map...case class Answer[Next](ans: String, n: Next) extends Quiz[Next] 6 implicit object QFunctor extends Functor...) 15 _ <- Push(5) 16 _ <- Mul() 17 } yield () //> ast : scalaz.Free...[[x]scalaz.Coyoneda[Exercises.interact.Calc,x],Unit] = Gosub() 从上面的AST表达方式可以估计到这是一个对Int进行加减乘除的计算器,应该是先通过
//> res0: Option[Int] = Some(22) 看,虽然换了个壳子(context), 但for-loop里的程序没有变化...实践证明如果这个F实现了flatMap,那么堆砌成的类型也能实现flatMap。好,scalaz的Option是实现了flatMap的,那么能不能把它和State堆砌在一起呢?...相信scalaz特别提供了这么个type class应该有它的用意。我的猜想是这个Monad是个功能比较完整的组合Monad。...看看它的map和flatMap是怎么实现的: def map[B](f: A => B)(implicit F: Functor[F]): IndexedStateT[F, S1, S2, B] = IndexedStateT...先传入一个端口号,在程序中可以重设使用的端口号: 1 val program: ReaderWriterState[Config, List[String], Int, Int] = for { 2
在前几期讨论中我们终于推导出了Free Monad。这是一个Monad工厂,它可以把任何F[A]变成Monad。可惜的是它对F[A]是有所要求的:F必须是个Functor。...除非把Console类型修改一下,这个可以参考前面讨论中的代码。 现在的问题是如果能有个什么方法把F[A]变成Functor,就像Free Monad那样有个Free Functor就好了。...范畴学中Yoneda lemma结论中的Coyoneda就是一个Free Functor。...[F]): F[A] = //Coyoneda转F需要F Functor实例 32 F.map(fi)(k) 33 def toYoneda(implicit F: Functor[F]):...我们在liftFU函数中需要借用scalaz的Unapply类型来分解出Coyoneda, S[A]然后施用在liftF; def liftF[S[_],A](sa: S[A])(implicit S:
在学习scalaz初期,FP的类型和函数施用搞得我很无奈,不适应:FP类型的Functor,Applicative,Monad等等给我的印象是无比抽象的。...当然,FP的递归算法又更加深了我们对现实中选用它的疑虑。但从Free Monad反向回顾scalaz的这些基础类型和函数,我好像渐渐地明白了它们在scalaz这个FP工具库中存在的意义。...通过证明,任何Monad都必须是Functor和Applicative,所以在scalaz里提供的Functor,Applicative以及其它的基础typeclass并不如我们想象的那样好像没什么实用价值...它可以把影响函数组合的副作用放到算法(interpret)阶段,让我们能够在算式中实现程序间的组合。...具体的语法集合以及多语法的效果实现对应运算可以参考前面这篇博客中的讨论。
我们实现了在运算flatMap过程中对log进行的累积。...那么我们就沿着惯用的套路获取一下KeyLog的MonadPlus实例。...KeyLog[K]的empty[K]是什么呢?想了半天没得到答案,可能KeyLog[K]就没有empty[K]吧。也许我们想取得KeyLog MonadPlu实例的目的还没搞清楚。...Scalaz为List,Option提供了MonadPlus实例,我们看看这两种类型的守卫函数使用: 1 for { //list 2 a 50 if a.shows contains...对于KeyLog[K],它只有一种状态,没有选择的需要,所以我无法实现KeyLog[K]的empty[K]。 List和Option的empty分别是:Nil和None,这个很容易理解。
1 为什么查看的ARP表项中没有VLAN信息?...如果ARP表项没有VLAN信息,那么代表这条表项中的接口处于三层模式,是一个三层口; 如果ARP表项有VLAN信息(并且表项中接口不是三层子接口时),那么代表这条表项中的接口处于二层模式,是一个二层口...2 案例 执行display arp等相关命令,可以查看ARP表项: 例如回显中IP地址为10.1.1.2,MAC地址为04f9-388d-e685,该ARP表项是从接口10GE1/0/3动态学习到的,...例如回显中IP地址为10.1.1.3,MAC地址为0023-0045-0067,该ARP表项是静态配置的,出接口是10GE1/0/3,VLAN编号是101。...例如回显中IP地址为10.1.1.5,MAC地址为306b-2079-2202,该ARP表项类型为I,表示IP地址10.1.1.5是接口10GE1/0/14的IP地址。
提供的Inject类型实例,用来把F[A]这种类型转换成G[A]。...现在这些升格了的语句集都具备了隐式实例implicit instance,随时可以在隐式解析域内提供操作语句支持。...我初步分析可能是因为scalaz对Free设下的门槛:F[A]必须是个Functor。...在lift函数的Inject[F,G]中,目标类型G[_]最终会被升格为Free Monad,如果我们使用Free.liftF函数的话G[_]必须是Functor。...最近新推出的Cats组件库中Free的定义不需要Functor,有可能解决这个问题。因为Free可能成为将来的一种主要编程模式,所以必须想办法解决多语句集联合使用的问题。不过我们把这个放到以后再说。
领取专属 10元无门槛券
手把手带您无忧上云