- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我目前正在学习 JavaScript。我遇到了这个问题,并尝试在 javacript 中使用柯里化(Currying)来解决它,但无法完全正确地解决它。
给定一个函数 pipe()
,它接受多个函数作为参数并返回一个新函数,该函数会将其参数传递给第一个函数,然后将结果传递给第二个函数,然后传递给第三个函数,依此类推,返回最后一个函数的输出。因此给定:例如,pipe(foo, bar, baz)(1, 2, 3)
等价于 baz(bar(foo(1,2,3)))
。
我将如何在 javascript 中解决这个问题?
最佳答案
函数式编程很有趣,所以我会试试这个。一般这个概念叫做function composition最好用在一元函数(只接受一个参数的函数)上。
在最基本的层面上,函数组合看起来像这样
const comp = f => g => x => f (g (x))
组成函数的列表是该列表的折叠,使用以id 函数开头的comp .
const id = x => x;
const foldl = f => y => xs =>
xs.length === 0 ? y : foldl (f) (f (y) (xs[0])) (xs.slice(1));
const compN = fs => foldl (comp) (id) (fs);
我们可以使用
let foo = x => x - 1;
let bar = x => x * 20;
let baz = x => x + 3;
compN ([foo, bar, baz]) (2);
//=> 99
那么它是如何工作的呢?
compN ([foo, bar, baz])
// returns: x => foo(bar(baz(x)))
因此,当我们对该返回值调用 (2)
时,2
将作为 x
传入,然后执行整个链
foo(bar(baz(2)))
foo(bar(5))
foo(100)
//=> 99
作为此实现的结果,您将获得 compN
以及 3 其他可重用函数,id
,comp
, 和 foldl
但是,您的问题在编写时考虑到了一些魔力。您的标准表明函数组合应该在入口处采用多个参数,因此这种通过引入丑陋的异常来混淆整个概念。不管怎样,这里有一种你可以写的方法
const id = x => x;
const foldl = f => y => xs =>
xs.length === 0 ? y : foldl (f) (f (y) (xs[0])) (xs.slice(1));
const badComp = f => g => (...xs) => f(g(...xs));
const pipe = fs => foldl (badComp) (id) (fs);
pipe ([x => x * x, (x,y) => x + y]) (2,3); //=> 25
//=> (2+3) * (2+3)
//=> 5 * 5
//=> 25
如您所见,这里的实用性甚至没有很大提高。如果你想向一个函数发送多个参数,你就不会将它们作为数组发送。因此,不要使用 foo(1,2)
,而是使用 foo([1,2])
。这样您就可以使用我的回答第一部分中描述的更受欢迎的一元函数组合。那么你就不必像剩余参数 (...xs) =>
和展开运算符 f(g(...xs))
那样依赖牙痛糖了。
此外,ES6 为您提供了解构赋值,因此您可以轻松地使用一元函数组合方法,并且仍然可以编写看似采用多个参数的方法。 pipe
示例可以使用 compN
重写
compN ([x => x * x, ([x,y]) => x + y]) ([2,3]);
是的,我的观点显然支持经典的一元函数组合,但您可以使用让您开心或完成家庭作业的任何一个。
无论如何,那是我自己的 2 美分。如果您有任何疑问,我很乐意为您提供帮助。
我不想用 compN
的初始实现让您不知所措,所以我使 foldl
函数保持简单。如果我要执行此操作,我实际上会更进一步。
const id = x => x;
const comp = f => g => x => f (g (x));
const eq = x => y => y === x;
const prop = x => y => y[x];
const len = prop ('length');
const isEmpty = comp (eq (0)) (len);
const first = xs => xs[0];
const rest = xs => (xs) .slice (1);
const foldl = f => y => xs =>
isEmpty (xs) ? y : foldl (f) (f (y) (first (xs))) (rest (xs));
const compN = fs => foldl (comp) (id) (fs);
当然它的工作原理是一样的
compN ([x => x - 1, x => x * 20, x => x + 3]) (2) //=> 99
作为此 compN
实现的结果,我们 免费 获得了 9 个其他完全可重用的函数。那是巨大的,imo。这意味着下次您必须定义另一个函数时,您可能已经完成了由这些其他函数定义的大部分工作。
此外,我选择实现 foldl
而不是依赖于原生的 Array.prototype.reduce
因为它不仅向您展示了如何通过递归实现迭代循环,而且还因为它需要一个柯里化(Currying)过程。
我的 foldl
使用原生 Array.prototype.reduce
的等价物是
var uncurry = f => (x,y) => f (x) (y);
var foldl2 = f => y => xs => xs.reduce(uncurry(f), y);
哪个都好。再次,选择你喜欢的。如果您最终选择了 Array.prototype.reduce
解决方案,至少您现在知道如何制作自己的^,^
非常激进的东西。好的,祝你好运,再见。
关于javascript - 给定一个函数 pipe(foo, bar, baz)(1, 2, 3),你如何实现它等同于 javascript 中的 baz(bar(foo(1,2,3)),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34363381/
我有管道输出 command_a | command_b | ... | command_n 输出是一个数字序列 4.2 -1 ... 0.2 我可以使用 gnuplot 绘制这些数字吗? (将 gn
关闭。这个问题是opinion-based 。目前不接受答案。 想要改进这个问题吗?更新问题,以便 editing this post 可以用事实和引文来回答它。 . 已关闭 6 年前。 Improv
我目前正在尝试连接父项和子项之间的管道。子级正在执行 sort 并对从父级接收到的输入进行排序。然后 children 写入一个单独的管道。每个进程有两个管道。一个这样 parent 可以将输入发送给
最近我正在研究 Python 中的并行编程工具。这是 os.pipe 和 multiprocessing.Pipe 之间的两个主要区别。(尽管它们被使用的场合) os.pipe是单向,multipro
我的站点上运行着 Yahoo Pipe,Romneyomics它使用来自 Delicious 和 Topsy 的饲料。Delicious 提要不提供“描述”字段,但 Topsy 提供,并且不仅仅是一个
我有一些使用管道的 Haskell 代码: module Main(main) where import Pipes a :: Producer Int IO () a = each [1..10]
所以标题几乎解释了我的问题。 stdout=subprocess.PIPE 和 stdout=PIPE 有什么区别?两者都来自 subprocess 模块,但为什么要使用一个而不是另一个呢?你如何使用
我有一个名为“myPipe”的自定义管道。我得到: The pipe 'myPipe' could not be found error 在我的单元测试中请建议在我的 .spec.ts 中导入和声明什
我有一个非常简单的 Python 3 脚本: f1 = open('a.txt', 'r') print(f1.readlines()) f2 = open('b.txt', 'r') print(f
我正在使用管道和 Python 的多处理模块在进程之间发送简单的对象。文档指出,如果管道已关闭,则调用 pipe.recv() 应该引发 EOFError。相反,我的程序只是阻塞在 recv() 上,
我在 perl 中见过这两种形式的管道 open。 一种是简单的管道打开 open FH,'| command'; 其他是安全管道打开 open FH,'|-','command'; 现在,第二个中的
我正在尝试对我的组件进行单元测试,但它立即生成一个错误: 类型错误:this.store$.pipe 不是函数 根据我的理解, createSpyObj 应该模拟状态。我有不同的选项选项,但没有一个起
我在这里看到这个帖子很多次了;但未能从命令中捕获故意错误。迄今为止我找到的最好的部分工作.. from Tkinter import * import os import Image, ImageTk
我正在编写一个简单的程序来解析编译器的输出并重新格式化任何错误消息,以便我们使用的 IDE(visual studio)可以解析它们。我们使用 nmake构建,它将使用如下命令行调用编译器: cc16
我有一个在coreos上运行的kubernetes集群。我希望在称为记录的Pod中的容器中运行journal2gelf https://github.com/systemd/journal2gelf。
为什么当管道中没有写入器时,读取器存在可以,但当管道中没有读取器时,写入器存在就不行? 。是不是因为reader需要等待,所以没有writer也没关系,而writer已经准备好数据了,即使数据准备好了
我在/etc/postfix/master.cf 中创建了一个 postfix 命令管道,其中包含一个在 STDOUT 和 STDERR 上产生输出的有效命令。在终端上调用时一切正常(因此在 STDO
我有一个命令需要来自管道的输入。例如,考虑著名的 cat 命令: $ echo Hello | cat Hello 假设我在 Perl 6 程序中有一个字符串,我想将其通过管道传递给命令: use v
因此,由于我们拥有各种设置,我习惯于遇到需要将一个可观察结果添加到另一个结果的地方,然后同时使用两者。我需要第一个在另一个之前完成的地方 getUser() .pipe( mergeMap
我在 Angular 5 中有一个非常简单的管道 import { Pipe, Injectable } from '@angular/core'; @Pipe({ name: "defaul
我是一名优秀的程序员,十分优秀!