函数式编程对象-自定义容器(用函数组合一)

   上一篇是用链式调用的方式使用Either,这一次我们尝试用函数组合,我们先使用ramda库里的composeK方法,它用于组合返回容器对象的函数(自动调用容器的chain方法来执行函数)

let R= require('ramda');

//先实现一个最轻量的Either
const Right = x =>({
        chain: f => f(x),
        map: f => Right(f(x)),
        getOrElse:()=>x,
        toString: () => `Right(${x})`,
        value:x,
        isRight:true
})

const Left = x => ({
        chain: f => Left(x),
        map: f => Left(x),
        getOrElse:(v)=>v,
        toString: () => `Left(${x})`,
        value:x,
        isRight:false
});

//1.合并判空
const fromNullable = v => v == null ? Left(v) : Right(v);
//再写一个高阶函数,用fromNullable使普通函数返回Either
const highFn = Fn => R.pipe(Fn,fromNullable);


//2.实现链式调用需要的一系列方法,根据业务来,我先随便写...
const getList = R.path(['obj','value']);
const formatProp = R.map(R.evolve({name:R.pipe(R.trim,R.toUpper)}));
const sortList = R.sortBy(R.prop('name'));

const getRes = R.composeK(
    highFn(sortList),
    highFn(formatProp),
    highFn(getList),
    fromNullable,
)

const result = getRes(obj);


console.log(result.value);

但是,这样调用并不好看,因为要用higeFn来饲养普通方法,已使得它们返回Either对象,这样的模版代码应该能去掉,这就必须自己来实现compose组合函数了,比如这样:

const compose = (...Fns)=> R.composeWith((Fn, res) => res.chain(highFn(Fn)) )(Fns);

我们使用了ramda的composeWith方法来自定义组合逻辑,在方法链的调用过程中自动饲养函数并自动调用容器的chain方法。

完整代码如下:

let R= require('ramda');

//先实现一个最轻量的Either
const Right = x =>({
        chain: f => f(x),
        map: f => Right(f(x)),
        getOrElse:()=>x,
        toString: () => `Right(${x})`,
        value:x,
        isRight:true
})

const Left = x => ({
        chain: f => Left(x),
        map: f => Left(x),
        getOrElse:(v)=>v,
        toString: () => `Left(${x})`,
        value:x,
        isRight:false
});

//1.合并判空
const fromNullable = v => v == null ? Left(v) : Right(v);
//再写一个高阶函数,用fromNullable使普通函数返回Either
const highFn = Fn => R.pipe(Fn,fromNullable);


//2.实现链式调用需要的一系列方法,根据业务来,我先随便写...
const getList = R.path(['obj','value']);
const formatProp = R.map(R.evolve({name:R.pipe(R.trim,R.toUpper)}));
const sortList = R.sortBy(R.prop('name'));


const compose = (...Fns)=> R.composeWith((Fn, res) => res.chain(highFn(Fn)) )(Fns);

const getRes = compose(
    sortList,
    formatProp,
    getList,
    fromNullable,
)
const obj = {
    obj:{
        value:[
            {name:'xx'},
            {name:'yy'}
        ]
        
    }
}
const result = getRes(obj);


console.log(result.value);

 

 

 

下面,来实现验证,还是用自定义的compose

let R= require('ramda');

//先实现一个最轻量的Either
const Right = x =>({
        chain: f => f(x),
        map: f => Right(f(x)),
        getOrElse:()=>x,
        toString: () => `Right(${x})`,
        value:x,
        isRight:true
})

const Left = x => ({
        chain: f => Left(x),
        map: f => Left(x),
        getOrElse:(v)=>v,
        toString: () => `Left(${x})`,
        value:x,
        isRight:false
});



//1.实现一个逻辑处理函数,逻辑是:遇到错误(Error对象)就终止执行(放入Left容器)。
const fromError = v => v instanceof Error ? Left(v) : Right(v);
const highFn = Fn => R.pipe(Fn,fromError);


//2.业务方法
const mobileReg = /^1[123456789]\d{9}$/;
const vEmpty = v => v.length !== 0 ? v : new Error('手机号码为必须项!');
const vMobile = v => mobileReg.test(v.trim()) ? v : new Error('请输入正确的手机号码!')

const compose = (...Fns)=> R.composeWith((Fn, res) => res.chain(highFn(Fn)) )(Fns);

//3.组合方法
const getResult = compose(
    vMobile,
    vEmpty,
    Right
)
const result = getResult('');
console.log(result.isRight);

还有一种执行逻辑,就是收集错误,这个要求方法链遇到错误也必须执行下去,Either目前满足不了,这很可能需要实现一个新的容器。我们先实现一个新容器,再尝试不用新容器而仍然用Either来执行这种逻辑,因为我们希望把Either当成一个万能的分支处理容器。

(以上代码都经过测试,直接可用。)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值