javascript – 在函数式编程中实现双向计数器?
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了javascript – 在函数式编程中实现双向计数器?,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4681字,纯文字阅读大概需要7分钟。
内容图文
![javascript – 在函数式编程中实现双向计数器?](/upload/InfoBanner/zyjiaocheng/819/a5cc092fe20945d89b1399921c146d33.jpg)
我试图围绕一些函数式编程基础知识.
因此,通过使用更高阶函数,我可以创建一个可以递增的计数器:
function counter( start ) {
var count = start;
return function() {
return ++count;
}
}
var myCounter = counter( 2 );
myCounter();
myCounter();
但是,实现双向计数器的正确方法(就功能编程而言)是什么?我想出了以下内容,但它对我来说似乎太像一个便宜的物体了:
function bicounter( start ) {
var count = start;
var mutate = function(amount) {
return function() { count += amount; }
};
return {
increment: mutate(1),
decrement: mutate(-1)
}
}
var myCounter = bicounter( 2 );
myCounter.increment();
myCounter.decrement();
解决方法:
功能编程完全是字面意思是“用函数编程”.在这里,我们谈论的是mathematical function而不是subroutine.有什么区别?
>这是一个功能(Ackermann function):
数学函数是纯粹的(即它没有副作用).数学函数只做一件事:它将输入值映射到输出值.它不会更改任何变量的值.
>这是一个计算Ackermann函数结果的子程序:
function A(m, n) {
var stack = [], exit;
do {
if (m > 0) {
m = m - 1;
while (n > 0) {
stack.push(m);
n = n - 1;
}
n = 1;
} else {
m = stack.pop();
n = n + 1;
}
} while (m !== exit);
return n;
}
子程序可能是也可能不是纯粹的.例如,上面的子程序是不纯的,因为它修改了变量m,n和堆栈.因此,虽然它计算了Ackermann函数的结果,这是一个数学函数,但它不是一个数学函数.
现在,考虑你的计数器功能:
function counter(count) {
return function () {
return ++count;
};
}
var countup = counter(0);
alert(countup()); // 1
alert(countup()); // 2
alert(countup()); // 3
这是函数式编程吗?简短的回答是,它是有争议的,因为你确实使用higher-order functions.但是,你的计数器功能不是一个数学函数.因此,在功能编程的严格定义中(即使用数学函数编程),您的程序并不是真正的功能.
注意:我认为大多数混淆都是因为JavaScript中的第一类子程序被称为函数.实际上,它们可以用作函数.但是,它们不是数学函数.
实际上,您的程序是面向对象的.每次调用计数器时,您都会创建一个代表计数器对象的新abstract data type.由于此对象只有一个操作定义,因此您可以从计数器函数返回该操作本身.因此,你的直觉是绝对正确的.这不是函数式编程.它是面向对象的编程.
那么如何使用函数式编程实现计数器呢?
在函数式编程中,一切都可以定义为函数.真奇怪.数字怎么样?好吧,numbers can be defined as functions too.一切都可以定义为一个功能.
但是,为了简单起见,我们假设我们有一些原始数据类型,比如Number,我们可以使用structural typing定义新的数据类型.例如,任何具有{count:Number}结构的对象(即具有单个属性的任何对象)命名计数,其类型为Number)是Counter类型的值.例如,考虑:
var counter = { count: 5 }; // counter :: Counter
打字判断计数器:: Counter读作“计数器是计数器类型的值”.
但是,编写构造函数来构造新的数据结构通常会更好:
// Counter :: Number -> Counter
function Counter(count) {
return { count: count };
}
var counter = Counter(5); // counter :: Counter
请注意,值Counter(它是Number – > Counter类型的函数,读作“Number to Counter”)与Counter类型(它是{count:Number}形式的数据结构)不同.类型和值可以具有相同的名称.我们知道他们是不同的.
现在,让我们编写一个返回计数器值的函数:
// count :: Counter -> Number
function count(counter) {
return counter.count;
}
这不是很有趣.但是,那是因为Counter数据类型本身并不是很有趣.实际上,Number数据类型和Counter数据类型是isomorphic(即我们可以使用函数Counter将任意数字n转换为等效计数器c,我们可以使用函数count将计数器c转换回数字n,并且反之亦然).
因此,我们可以避免定义Counter数据类型并使用Number本身作为计数器.但是,出于教学目的,让我们为Counter使用单独的数据类型.
所以,现在我们想要使用名为increment的函数更新计数器的值.坚持,稍等.函数不能改变函数式编程中的变量值.我们如何更新计数器的价值?好吧,我们无法更新计数器的价值.但是,我们可以返回一个具有更新值的新计数器.这正是我们在函数式编程中所做的:
// increment :: Counter -> Counter
function increment(counter) {
return Counter(count(counter) + 1);
}
同样,我们可以定义减量函数:
// decrement :: Counter -> Counter
function decrement(counter) {
return Counter(count(counter) - 1);
}
请注意,如果我们使用数字作为计数器,则计数器c的递增和递减操作将分别定义为c 1和c – 1.这进一步加强了我们对计数器只是一个数字的理解.
这都是花花公子,但函数式编程有什么意义呢?
目前,似乎函数式编程比普通编程更难.毕竟,有时你真的需要突变来编写有趣的程序.例如,您可以使用函数式编程轻松完成此操作吗?
function bicounter(count) {
return {
increment: update(+1),
decrement: update(-1)
};
function update(amount) {
return function () {
return count += amount;
};
}
}
var counter = bicounter(0);
alert(counter.increment()); // 1
alert(counter.decrement()); // 0
实际上,是的,你可以使用State monad来做到这一点.我将切换到Haskell,因为缺少比JavaScript更好的函数式编程语言:
import Control.Monad.State
type Counter = Int
counter :: Counter
counter = 0
increment = modify (+1)
decrement = modify (subtract 1)
alert = get >>= (liftIO . print)
program = do
increment
alert
decrement
alert
main = evalStateT program counter
这是一个可运行的Haskell程序.相当简洁不是吗?这是函数式编程的强大功能.如果按照功能编程的想法出售,那么你一定要考虑learning Haskell.
内容总结
以上是互联网集市为您收集整理的javascript – 在函数式编程中实现双向计数器?全部内容,希望文章能够帮你解决javascript – 在函数式编程中实现双向计数器?所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。