计算机范畴论(javaScript实践版)第二篇

前言

上一篇讲解了JavaScript这种语言在函数式方面基本功能,下面继续讲解范畴论的使用。现在的范畴论已经发展的很迅速了,计算机领域的应用也越来越广泛,但是早起的JavaScript虽然是函数式的,但是并未在范畴论方面发力,因此很多内置函数都是不安全的(非纯函数的)。
下面我们从头开始进行讲解,如果跟着我一起做,你也能写出一个类似于java的Stream的一样的库函数。
当然本文的事例为了支持早期浏览器,并未做多线程版本的实现,如果读者精力充沛,可以自行实现。

1. 你只管输入的机器

人类为了提高生产力,总是发明了各种各样的机器,放入原料,等待结果就好。
对于程序员的api来讲,最让人稀罕的就是那种输入几个参数,你就能得到结果的安全函数了(背后是大量的api制造者和测试人员的检测通过的)。因此函数式编程第一要素就是安全。
为了实现这个目标,所有的执行我们都要放入一个机器中(容器),然后我们一顿按按钮(告诉容器要执行什么),最后在输出端拿到结果就好了。
我们为了方便理解,这里直接用市面上通用的命名方法来命名吧。

首先定义一个容器,我们叫它Stream吧。
然后定义一个获取值f方法,我们总归是需要一个输出啊,不管你用不用,函数起码会返回一个void。

var Stream=function(){
     
  this.value=null;//初始值
  this.f=function(){
     //值获取器
  };
};

我们再继续想想这个容器还需要啥,对,输入。
最好我们也能顺道初始化了它,此时这个容器(机器)是没有任何任务的,所以你总能获得一个原始值的输出。

Stream.of=function(){
     
  var s=new Stream();
  //初始化值
  if(arguments.length>0){
     
  	s.value=arguments[0];
  }
  //值获取器
  s.f=function(){
     
    return s.value;
  }
  return s;
};

从命名来看方法f简单粗暴,肯定不是一个合格的api命名,我们当做是一个内部方法把,后面我们用闭包来优化一下这个。因此我们还需要来个输出的方法。当然柯里化要在这里体现一下,把延迟计算做好。

Stream.prototype.get=function(){
     
	//调用唯一的输出函数,有延迟计算的功效
  	var value=this.f();
  	//重置value为null
  	this.value=null;
  	//重置输出函数
  	this.f=function(){
     
 	};
 	//返回结果
 	return value;
};

为什么要重置?为了防止程序员的乱使用,数据总是在变化的,用到的时候在重新初始化。这个我们在后面解释吧。

2. 第一个烟花

还记得上篇中的加法的那个纯函数示例吧,我们现在给我的容器增加一个万能的map方法,用范畴论的风格来实现加法的功能。

Stream.prototype.map=function(v){
     
	var f=this.f;
  	var t=this;
  	var map=function(){
     
    	var value=f();
		if(value){
     
	  	return v(value);
		}
  	}
  	this.f=map;
  	return this;
};

测试代码。

var one=1;
var addOne=x=>x+1;
var r=Stream.of(one).map(addOne).get();//2
console.info(one);
console.info(addOne);
console.info(r);

var r1=Stream.of(one).map(addOne).map(addOne).get();//3
console.info(one);
console.info(addOne);
console.info(r1);

可以看到无论你如何操作map,操作多少次map都不会修改示例中的one的值,它永远都是1,同样addOne方法也不会被改变。这是很安全的(纯函数的)。当然现在的JavaScript很喜欢意大利面式的方法调用,这很函数式。
你永远只是把输入放入盒子中(of方法),然后告诉盒子要干什么(map方法),最后得到结果(get方法)。就这样我们通过这套api就很容易的做到了纯函数。

未完待续

你可能感兴趣的:(JavaScript,函数式,算法与数据结构)