zoukankan      html  css  js  c++  java
  • 函数式编程(三):组合函数

    其他:

    函数式编程(一):纯函数

    函数式编程(二):curry

    前面说到 curry,而 curry 与 compose(组合)是一对好基友,curry 函数的很大价值体现在它对于 compose 的友好性。组合的思想在于把小的单元逻辑合成一个程序,1+1>2。

    在数学里,函数 f 和 g 的组合定义为 f( g(x) ),在 JavaScript 中就是这样了

    var compose = function(f, g) {
    	return function(x) {
    		return f(g(x));
    	};
    };

    可以看成 x 在函数 f,g之间通过“管道”传输,来看一个例子。

    var head = function(x) {
    	return x[0];
    };
    var reverse = reduce(function(acc, x) {
    	return [x].concat(acc);
    }, []);
    var last = compose(head, reverse);
    last(['jumpkick', 'roundhouse', 'uppercut']);
    //=>	'uppercut'

    你是否注意到 reverse 函数最先被应用?这很重要,函数是从右向左应用的。(从右往左执行更能反映数学上的定义)。组合函数有一个强大的特性——结合律。这意味着任何一个函数分组都可以拆开来,然后再以它们自己的组合方式打包在一起,这给我们带来了强大的灵活性。

    var toUpperCase = function(x) {
    	return x.toUpperCase();
    };
    var exclaim = function(x) {
    	return x + '!';
    };
    
    compose(toUpperCase, compose(head, reverse));
    // 或者
    compose(compose(toUpperCase, head), reverse);
    
    //因为如何为 compose 的调用分组不重要,所以结果都是一样的。这也让我们有//能力写一个可变的组合(variadic compose),用法如下:
    // 前面的例子中我们必须要写两个组合才行,但既然组合是符合结合律的,我们// 就可以只写一个,
    // 而且想传给它多少个函数就传给它多少个,然后让它自己决定如何分组。
    var lastUpper = compose(toUpperCase, head, reverse);
    
    lastUpper(['jumpkick', 'roundhouse', 'uppercut']);
    //=> 'UPPERCUT'
    
    
    var loudLastUpper = compose(exclaim, toUpperCase, head, reverse)
    
    loudLastUpper(['jumpkick', 'roundhouse', 'uppercut']);
    //=> 'UPPERCUT!'
    
    //	或
    var	last	=	compose(head,	reverse);
    var	angry	=	compose(exclaim,	toUpperCase);
    var	loudLastUpper	=	compose(angry,	last);
    //	更多变种...

    关于如何组合,并没有标准的答案——我们可以按自己喜欢的方式搭乐高积木。一般最佳实践是让组合可重用。

    #compose与curry

    来看一个例子:

    HTML代码部分:

    <!DOCTYPE html>
    <html lang="en">
    <head>
    	<meta charset="UTF-8">
    	<title>Document</title>
    	<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.11/require.min.js"></script>
    	<script src='flickr.js'></script>
    </head>
    <body>
    	
    </body>
    </html>

    js部分:

    requirejs.config({
    	paths: {
    		ramda: 'https://cdnjs.cloudflare.com/ajax/libs/ramda/0.13.0/ramda.min',
    		jquery: 'https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min'
    	}
    });
    
    // prop 函数的实现
    // var prop = _.curry(function(property, object){
    //   return object[property];
    // });
    
    require([
    		'ramda',
    		'jquery'
    	],
    	function(_, $) {
    		//utils
    		var Impure = {
    			getJSON: _.curry(function(callback, url) {
    				$.getJSON(url, callback);
    			}),
    
    			setHtml: _.curry(function(sel, html) {
    				$(sel).html(html);
    			})
    		};
    
    		var img = function(url) {
    			return $('<img/>', {
    				src: url
    			});
    		};
    
    		var trace = _.curry(function(tag, x) {
    			console.log(tag, x);
    			return x;
    		});
    
    		var url = function(t) {
    			return 'https://api.flickr.com/services/feeds/photos_public.gne?tags=' + t + '&format=json&jsoncallback=?';
    		};
    
    		var mediaUrl = _.compose(_.prop('m'), _.prop('media')); 
    
    		var srcs = _.compose(_.map(mediaUrl), _.prop('items'));
    
    		var images = _.compose(_.map(img), srcs);
    
    		var renderImages = _.compose(Impure.setHtml('body'), images);
    
    		var app = _.compose(Impure.getJSON(trace(renderImages), url);
    		// var app = _.compose(Impure.getJSON(trace(trace('response')), url);
    
    		app('cats');
    
    });

    通过 curry 与 组合 搭建起一个简单的应用,请求 Flickr 图片,并加载到页面上。。

  • 相关阅读:
    [转]用asp.net实现远程获取其他网站页面指定内容
    Occupation career planning
    【原创】Self-Contained Container(自包含容器)
    Kindle 转换器
    Win32 多线程学习笔记
    OC学习心得【适合初学者】
    OC-通讯录
    植物大战僵尸
    三、属性和点语法
    二十、函数指针高级(动态调用)
  • 原文地址:https://www.cnblogs.com/hwencc/p/5058698.html
Copyright © 2011-2022 走看看