将数据处理的过程定义成与数据无关的合成运算,不需要代表数据的那个参数,主要吧简单的运算步骤合成到一起,在使用这种模式之前,我们需要定义一些辅助的基本运算函数
const fp = require('loadsh/fp')
const f = fp.flowRight(fp.join('-'),fp.map(_.toLower),fp.split(' '))
HELLO WORD ==> hello_word
普通方式
function func1(str){
return str.toLowerCase().replace(/\s+/g,'_')
}
console.log(func1('HELLO WORD')) // hello_word
Point Free
const fp = require('loadsh/fp')
const func2 = fp.flowRight(fp.replace(/\s+/g,'_'),fp.toLower)
console.log(func2('HELLO WORD')) // hello_word
word wild web ==> W.W.W
const fp = require('loadsh/fp')
const firstLetterToUpper = fp.flowRight(fp.join('.'),fp.map(fp.flowRight(fp.toUpper,fp.first)),fp.split(' '))
console.log(firstLetterToUpper('word wild web')) // W.W.W
把副作用控制在可控的范围内以及异常处理、异步操作等
class Container {
constructor(value){
this._value = value
}
map(fn){
return Container.of(fn(this._value))
}
static of(value){
return new Container(value)
}
}
let r = Container.of(1).map(x=>x+1).map(x=>x*x)
console.log(r) // 4
class Container {
constructor(value){
this._value = value
}
map(fn){
return Container.of(fn(this._value))
}
static of(value){
return new Container(value)
}
}
Container.of(null).map(x=>x.toUpperCase()) //报错
// 输入为null 会触发副总用
class Mybe {
static of (value) {
return new Mybe(value)
}
constructor(value) {
this._value = value
}
map(fn) {
return this.isNothing() ? Mybe.of(null) : Mybe.of(fn(this._value))
}
isNothing() {
return this, this._value === null || this._value === undefined
}
}
const r1 = Mybe.of('hello word').map(x=>x.toUpperCase()) // null
const r2 = Mybe.of(null).map(x=>x.toUpperCase()) // null
console.log(r1) // Mybe { _value: 'HELLO WORD' }
console.log(r2) // Mybe { _value: null }
MyBe 函子问题 多次出现null后无法确定 null出现的位置
class Mybe {
static of (value) {
return new Mybe(value)
}
constructor(value) {
this._value = value
}
map(fn) {
return this.isNothing() ? Mybe.of(null) : Mybe.of(fn(this._value))
}
isNothing() {
return this, this._value === null || this._value === undefined
}
}
const r1 = Mybe.of('hello word')
.map(x=>x.toUpperCase())
.map(x=>null)
.map(x=>x.split(' '))
.map(x=>null)
.map(x=>x.split(' '))
console.log(r1) // Mybe { _value: null }
class Left {
static of (value) {
return new Left(value)
}
constructor(value) {
this._value = value
}
map(fn) {
return this
}
}
class Right {
static of (value) {
return new Right(value)
}
constructor(value) {
this._value = value
}
map(fn) {
return Right.of(fn(this._value))
}
}
function parseJosn(str){
try {
return Right.of(JSON.parse(str))
} catch (e) {
return Left.of({err:e.message})
}
}
const r = parseJosn('{ name zs }').map(x=>x.name.toUpperCase())
console.log(r) // Left { _value: { err: 'Unexpected token n in JSON at position 2' } }
const r2 = parseJosn('{ "name":"zs"}').map(x=>x.name.toUpperCase())
console.log(r2) // Right { _value: 'ZS' }
const fp = require('loadsh/fp')
class IO {
static of (value){
return new IO(()=>{
return value
})
}
constructor(fn){
this._value=fn
}
map(fn){
return new IO(fp.flowRight(fn,this._value))
}
value(){
return this._value()
}
}
// 当前在node环境中 调用
const r = IO.of(process).map(process=>process.execPath)
console.log(r) // IO { _value: [Function (anonymous)] }
console.log(r.value()) // /Users/zhaozhongyang/.nvm/versions/node/v13.13.0/bin/node
一个标准的函数式编程库
基本使用
const {
compose,
curry
} = require('folktale/core/lambda')
const _ = require("loadsh")
// curry 需要传递两个参数 第一个参数是传入函数的所需参数数量
let f = curry(2,(x,y)=>x+y)
console.log(f(1)(2)) // 3
// compose函数与 loadsh中的 flowRight 基本一致
let f2 = compose( _.toUpper,_.first)
console.log(f2(['a','b'])) // A
const { task } =require('folktale/concurrency/task')
const fs = require('fs')
const fp = require('loadsh/fp')
// 文件处理使用task 函子
const readFile = (filename)=>task(resolver=>{
fs.readFile(filename,'utf-8',(err,data)=>{
if(err){
resolver.reject(err)
}
resolver.resolve(data)
})
})
readFile("package.json")
.map(fp.split('\n'))
.map(fp.find(x=>x.includes('version')))
.run()
.listen({
onRejected:err=>{
console.log(err)
},
onResolved:val=>{
console.log(val) // "version":"2.0.1",
}
})
class Container {
constructor(value){
this._value = value
}
map(fn){
return new Container(fn(this._value))
}
}
函子嵌套
// 模拟 linux cat 命令
const readFile = (filename)=>new IO(()=>{
return fs.readFileSync(filename,'utf-8')
})
const print = (x)=>new IO(()=>{
console.log(x._value())
return x
})
const cat = fp.flowRight(print,readFile)
const f = cat('package.json')._value()._value()
console.log(f)
实现方式 扁平化处理
const fs = require('fs')
const fp = require('loadsh/fp')
class IO {
static of (value){
return new IO(()=>{
return value
})
}
constructor(fn){
this._value=fn
}
map(fn){
return new IO(fp.flowRight(fn,this._value))
}
join(){
return this._value()
}
flatMap(fn){
return this.map(fn).join()
}
}
// 模拟 linux cat 命令
const readFile = (filename)=>new IO(()=>{
return fs.readFileSync(filename,'utf-8')
})
const print = (x)=>new IO(()=>{
return x
})
const f = readFile('package.json').map(x=>fp.toUpper(x)).flatMap(print).join()
console.log(f)