max*_*nan 5 javascript functional-programming side-effects
函数式编程是否具有此逻辑的标准结构?
const passAround = (f) => (x) => {
f(x);
return x;
};
Run Code Online (Sandbox Code Playgroud)
这使我能够组合具有副作用且没有返回值的函数,例如console.log.它不像任务,因为我不想表示副作用的状态.
如果您正在谈论纯函数式编程,那么您需要挑战这个起点:
具有副作用且没有返回值的函数
在函数式编程中,没有这样的东西.每个函数都被定义为某些输入转换为某些输出.
所以显而易见的问题是,如果console.log没有副作用,你会如何表示?要回答,我们需要在您的问题中挑战另一个假设:
我不想代表副作用的状态
这正是函数式编程代表问题的方式:将输入和输出视为"世界状态".换句话说,给定函数之前的世界状态,返回函数之后的世界状态.在这种情况下,您将表示控制台的状态:给定具有x行输出的控制台,返回具有x + 1行输出的控制台.粗略地说,你可以这样写:
(x, console) => { return [x, console.withExtraLine(x)]; }
Run Code Online (Sandbox Code Playgroud)
通常用于表示它的更强大的机制称为"monad" - 一种特殊的对象,它包含一系列步骤以及一些额外的含义.在IOmonad 的情况下,每一步都包含一个将改变世界状态的动作.(I/O只是monad概念的许多有用应用之一.)
您将这些步骤编写为仅了解该状态某些部分的"展开"值的函数(例如,最终来自用户输入的参数),并且monad处理实际执行该函数领域之外的混乱细节计划.因此,不要将输入和输出视为"世界状态",而是将输入视为"计算链",将输出视为"稍微长一点的计算链".
有很多介绍都比我能给出的要好得多,只需要搜索"monad"或"functional programming io".
另请参阅此答案,此问题以及可能在查看此问题时自动生成的"相关"侧栏中的许多其他问题.
您可能会对SKI组合器演算感兴趣。让我们假设它f始终是一个纯函数:
const S = g => f => x => g(x)(f(x)); // S combinator of SKI combinator calculus
const K = x => y => x; // K combinator of SKI combinator calculus
const passAround = S(K); // Yes, the passAround function is just SK
console.log(passAround(console.log)(10) + 20);Run Code Online (Sandbox Code Playgroud)
无论如何,我之所以提出 SKI 组合器演算,是因为我想向您介绍Applicative Functors的概念。特别地,Reader应用函子等价于 SKI 组合子演算。组合S器相当于 的ap方法Reader,K组合器相当于pure的方法Reader。
在 JavaScript中,相当于Reader. Function因此,我们可以在 JavaScript 中定义apand purefor 函数,如下所示:
Function.prototype.ap = function (f) {
return x => this(x)(f(x));
};
Function.pure = x => y => x;
const print = Function.pure.ap(console.log);
console.log(print(10) + 20);Run Code Online (Sandbox Code Playgroud)
但是等等,您可以使用应用函子做更多的事情。每个应用函子也是一个函子。这意味着应用函子也必须有一个map方法。因为Reader方法map只是函数组合。它相当于B组合器。使用mapyou 可以做一些非常有趣的事情,例如:
Function.prototype.ap = function (f) {
return x => this(x)(f(x));
};
Function.pure = x => y => x;
const id = x => x; // I combinator of SKI combinator calculus
Function.prototype.map = function (f) {
return x => this(f(x));
};
Function.prototype.seq = function (g) {
return Function.pure(id).map(this).ap(g);
};
const result = console.log.seq(x => x + 20);
console.log(result(10));Run Code Online (Sandbox Code Playgroud)
该seq函数实际上相当于(*>)Applicative类的方法。这实现了方法级联的函数式风格。