# 函数式编程相识一下（下）

## 回忆柯里化、偏运用

``````let curry = (fn) =>{
if(typeof fn !== 'function'){
throw Error('No Function');
}

return function curriedFn(...args){
if(args.length < fn.length){
return function(){
return curriedFn.apply(null,args.concat([].slice.call(arguments)));
}
}
return fn.apply(null,args);
}
}

function add (a,b,c) { return a+b+c }

``````const partial = function (fn,...partialArgs){
let args = partialArgs;
return function(...fullArgs){
let arg = 0;
for(let i = 0; i<args.length && fullArgs.length;i++){
if(arg[i] === undefined){
args[i] = fullArgs[arg++];
}
}
return fn.apply(null,args)
}
}

let delayTenMs = partial(setTimeout , undefined , 10);

delayTenMs(() => console.log('this is Nealyang'));``````

## 组合、管道

bingo~

### compose 函数的完成

``````const compose = (a,b)=>(c)=>a(b(c));

let splitIntoSpaces = (str) => str.split(" ");

let count = (array) => array.length;

const countWords = compose(count,splitIntoSpaces);

countWords('Hello , I am Nealyang');``````

``````let map = (array,fn) => {
let results = []
for(const value of array)
results.push(fn(value))

return results;
};
let filter = (array,fn) => {
let results = []
for(const value of array)
(fn(value)) ? results.push(value) : undefined

return results;
};
let apressBooks = [
{
"id": 111,
"title": "C# 6.0",
"author": "ANDREW TROELSEN",
"rating": [4.7],
"reviews": [{good : 4 , excellent : 12}]
},
{
"id": 222,
"title": "Efficient Learning Machines",
"author": "Rahul Khanna",
"rating": [4.5],
"reviews": []
},
{
"id": 333,
"title": "Pro AngularJS",
"rating": [4.0],
"reviews": []
},
{
"id": 444,
"title": "Pro ASP.NET",
"rating": [4.2],
"reviews": [{good : 14 , excellent : 12}]
}
];

const compose = (a, b) =>
(c) => a(b(c))

const partial = function (fn,...partialArgs){
let args = partialArgs.slice(0);
return function(...fullArguments) {
let arg = 0;
for (let i = 0; i < args.length && arg < fullArguments.length; i++) {
if (args[i] === undefined) {
args[i] = fullArguments[arg++];
}
}
return fn.apply(this, args);
};
};

console.log("挑选效果",map(filter(apressBooks, (book) => book.rating[0] > 4.5),(book) => {
return {title: book.title,author:book.author}
}))
//东西类函数
let filterOutStandingBooks = (book) => book.rating[0] === 5;
let filterGoodBooks = (book) =>  book.rating[0] > 4.5;
let filterBadBooks = (book) => book.rating[0] < 3.5;

let projectTitleAndAuthor = (book) => { return {title: book.title,author:book.author} }
let projectAuthor = (book) => { return {author:book.author}  }
let projectTitle = (book) => { return {title: book.title} }

let queryGoodBooks = partial(filter,undefined,filterGoodBooks);
let mapTitleAndAuthor = partial(map,undefined,projectTitleAndAuthor)

let titleAndAuthorForGoodBooks = compose(mapTitleAndAuthor,queryGoodBooks)

console.log(titleAndAuthorForGoodBooks(apressBooks))

let mapTitle = partial(map,undefined,projectTitle)
let titleForGoodBooks = compose(mapTitle,queryGoodBooks)

//console.log(titleForGoodBooks(apressBooks))``````

### 多个函数的组合

``const compose = (...fns) => (value) => reduce(fns.reverse(),(acc , fn ) => fn(acc),value);``

``reduce(fns.reverse(),(acc , fn ) => fn(acc),value)``

``````const composeN = (...fns) =>
(value) =>
reduce(fns.reverse(),(acc, fn) => fn(acc), value);

const pipe = (...fns) =>
(value) =>
reduce(fns,(acc, fn) => fn(acc), value);

let oddOrEven = (ip) => ip % 2 == 0 ? "even" : "odd"
var oddOrEvenWords = composeN(oddOrEven,count,splitIntoSpaces);
let count = (array) => array.length;

oddOrEvenWords = pipe(splitIntoSpaces,count,oddOrEven);

## 函子

### 一步步梳理观点

``````const Container = function(val){
this.value = val;
}``````

``````Container.of = function(val){
return new Container(val);
}``````

``````Container.property.map = function(fn){
return Container.of(fn(this.value));
}``````

### MayBe 函子

MayBe函子可以让我们可以以越发函数式的体式格局处置惩罚毛病

``````const MayBe = function(val) {
this.value = val;
}

MayBe.of = function(val) {
return new MayBe(val);
}

MayBe.prototype.isNothing = function() {
return (this.value === null || this.value === undefined);
};

MayBe.prototype.map = function(fn) {
return this.isNothing() ? MayBe.of(null) : MayBe.of(fn(this.value));
};

console.log("MayBe chaining",MayBe.of("George")
.map((x) => x.toUpperCase())
.map((x) => "Mr. " + x))

console.log("MayBe chaining null",
MayBe.of("George")
.map(() => undefined)
.map((x) => "Mr. " + x))``````

### MayBe函子的用处

``````let value = 'string';
if(value != null || value != undefind){
return value.toupperCase();
}

//实际项目中的例子
getPageModuleData = () => {
return this.getDataFromXctrl(pageData.moduleData).then(moduleData => {
if (moduleData.filter.data.hotBrands.length) {
this.setState({
moduleData: moduleData.filter.data
});
}
// 小于多少个拍品，举行引荐
if (
moduleData &&
moduleData.list &&
moduleData.list.data &&
moduleData.list.data.settings &&
moduleData.list.data.settings.length
) {
this.recLimit = moduleData.list.data.settings[0].showRecLimit;
}
if (!this.recLimit) {
this.recLimit = 5; // 兜底
}
});
};``````

``````MayBe.of('Nealyang')
.map((x)=>x.toUpperCase())
.map(x=>`Mr.\${x}`);``````

1： 纵然给map传入返回null或许undefined的函数，MayBe也照旧可以处置惩罚

2：一切的map函数都邑挪用，不管他是不是接收到null or undefined

### 实际操刀

``````var request = require('sync-request');
...

let getTopTenSubRedditPosts = (type) => {

let response
try{
response = JSON.parse(request('GET',"https://www.reddit.com/r/subreddits/" + type + ".json?limit=10").getBody('utf8'))
}catch(err) {
response = { message: "Something went wrong" , errorCode: err['statusCode'] }
}
return response
}

let getTopTenSubRedditData = (type) => {
let response = getTopTenSubRedditPosts(type);
return MayBe.of(response).map((arr) => arr['data'])
.map((arr) => arr['children'])
.map((arr) => arrayUtils.map(arr,
(x) => {
return {
title : x['data'].title,
url   : x['data'].url
}
}
))
}

console.log("准确的接收到返回：",getTopTenSubRedditData('new'))
console.log("毛病时刻的状况",getTopTenSubRedditData('neww'))
//MayBe{value:[{title:...,url:...},{}...]}``````

### Either函子

``````const Nothing = function(val) {
this.value = val;
};

Nothing.of = function(val) {
return new Nothing(val);
};

Nothing.prototype.map = function(f) {
return this;
};

const Some = function(val) {
this.value = val;
};

Some.of = function(val) {
return new Some(val);
};

Some.prototype.map = function(fn) {
return Some.of(fn(this.value));
}

const Either = {
Some : Some,
Nothing: Nothing
}``````

``````console.log("Something example", Some.of("test").map((x) => x.toUpperCase()))
console.log("Nothing example", Nothing.of("test").map((x) => x.toUpperCase()))``````

``````let getTopTenSubRedditPostsEither = (type) => {

let response
try{
response = Some.of(JSON.parse(request('GET',"https://www.reddit.com/r/subreddits/" + type + ".json?limit=10").getBody('utf8')))
}catch(err) {
response = Nothing.of({ message: "Something went wrong" , errorCode: err['statusCode'] })
}
return response
}

let getTopTenSubRedditDataEither = (type) => {
let response = getTopTenSubRedditPostsEither(type);
return response.map((arr) => arr['data'])
.map((arr) => arr['children'])
.map((arr) => arrayUtils.map(arr,
(x) => {
return {
title : x['data'].title,
url   : x['data'].url
}
}
))
}

console.log("准确的运转： ",getTopTenSubRedditDataEither('new'))
console.log("毛病：",getTopTenSubRedditDataEither('new2'))//Nothing{value:{ message: "Something went wrong" , errorCode: err['statusCode'] }}``````

### MayBe 版本完成

#### 第一步的完成

``````let searchReddit = (search) => {
let response
try{
response = JSON.parse(request('GET',"https://www.reddit.com/search.json?q=" + encodeURI(search) + "&limit=2").getBody('utf8'))
}catch(err) {
response = { message: "Something went wrong" , errorCode: err['statusCode'] }
}
return response
}

let response
try {
} catch(err) {
console.log(err)
response = { message: "Something went wrong" , errorCode: err['statusCode'] }
}

return response
}``````

#### 第二步的完成

``````let mergeViaMayBe = (searchText) => {
let redditMayBe = MayBe.of(searchReddit(searchText))
let ans = redditMayBe
.map((arr) => arr['data'])
.map((arr) => arr['children'])
.map((arr) => arrayUtils.map(arr,(x) => {
return {
title : x['data'].title,
}
}
))
.map((obj) => arrayUtils.map(obj, (x) => {
return {
title: x.title,
}
}))

return ans;
}``````

### 说说题目

``````let answer = mergeViaMayBe("functional programming")

/*
须要两次map才拿到我们想要的
*/
arrayUtils.map(result,(mergeResults) => {
console.log(comment)
})
})
})``````

``````let example=MayBe.of(MayBe.of(5));
//将value 加 4 的需求
example.map(x=>x.map(v=>v+4))
//MayBe{value:MayBe{value:9}}``````

### join 来也

``````MayBe.prototype.join = function(){
return this.isNothing?MayBe.of(null):this.value
}``````

``````let example=MayBe.of(MayBe.of(5));
example.join().map(v=>v+4);//=> MayBe(value:9)``````

``````let mergeViaJoin = (searchText) => {
let redditMayBe = MayBe.of(searchReddit(searchText))
let ans = redditMayBe.map((arr) => arr['data'])
.map((arr) => arr['children'])
.map((arr) => arrayUtils.map(arr,(x) => {
return {
title : x['data'].title,
}
}
))
.map((obj) => arrayUtils.map(obj, (x) => {
return {
title: x.title,
}
}))
.join()

return ans;
}

``````MayBe.prototype.chain = function(f){
return this.map(f).join()
}
...
let mergeViaChain = (searchText) => {
let redditMayBe = MayBe.of(searchReddit(searchText))
let ans = redditMayBe.map((arr) => arr['data'])
.map((arr) => arr['children'])
.map((arr) => arrayUtils.map(arr,(x) => {
return {
title : x['data'].title,
}
}
))
.chain((obj) => arrayUtils.map(obj, (x) => {
return {
title: x.title,
return x.length
})
}
}))

return ans;
}

//trying our old problem with chain

## 结束语

原文作者：isNealyang
原文地址: https://segmentfault.com/a/1190000015597564
本文转自网络文章，转载此文章仅为分享知识，如有侵权，请联系博主进行删除。