JavaScript函数由链接组成

我检查了重复问题的可能性,并找不到确切的解决scheme。

我用JavaScript写了一些函数链代码,效果很好。

var log = function(args) { console.log(args) return function(f) { return f; }; }; (log('1'))(log('2'))(log('3'))(log('4')); //1 //2 //3 //4 

我想做这个懒惰的评价。

或者撰写function。

 var log = function(args) { var f0 = function() { return console.log(args); }; return function(f1) { return function() { f0(); return f1; }; }; }; var world = (log('1'))(log('2'))(log('3'))(log('4')); console.log(world); //should be just a function, // but in fact //1 //[function] world(); //should be //1 //2 //3 //4 // but in fact // 2 

有些事情是非常错误的。 你能修好它吗?

谢谢。

这个问题已经解决了,但还有更多

asynchronous问题,如评论讨论中所示

当我们有

 // unit :: a -> IO a var unit = function(x) { return function() { return x; }; }; // bind :: IO a -> (a -> IO b) -> IO b var bind = function(x, y) { return function() { return y(x())(); }; }; // seq :: IO a -> IO b -> IO b var seq = function(x, y) { return function() { return x(), y(); }; }; var action = function(x) { return function(y) { return y ? action(seq(x, y)) : x(); }; }; var wrap = function(f) { return function(x) { return action(function() { return f(x); }); }; }; var log = wrap(console.log); // -- runtime -- // HACK: when `world` is modified by passing a function, // the function will be executed. Object.defineProperties(window, { world: { set: function(w) { return w(); } } }); 

我们也经常需要asynchronous连锁反应。

 var asyncF = function(callback) { setTimeout(function() { for (var i = 0; i < 1000000000; i++) { }; callback("async process Done!"); }, 0); }; var async = wrap(asyncF(function(msg) { world = log(msg); return msg; })); 

现在,

 world = (log(1))(async)(log(3)); //1 //3 //async process Done! 

目前为止,我们尝试使用绑定

 world = (log(1)) (bind((async), (log(x)))); //should be //1 //async process Done! //3 //in fact //ReferenceError: x is not defined 

你可以修改来做这个工作吗?

还有一个关于retrun x, y; 多重价值

我不明白

  // seq :: IO a -> IO b -> IO b var seq = function(x, y) { return function() { return x(), y(); }; }; 

正如图书馆作者所提到的那样

请注意,这在Haskell中是不可能的,因为一个函数不能返回两个结果。 另外,在我看来,它看起来很丑。

我同意,不知道这是什么

return x(), y();

多重返回值。

我在这里search和search,但找不到答案。

这是什么??

(以防万一,我会select这个黑客的语法)

谢谢!

所以如果我正确地理解了这个问题,你想要在JavaScript中链接IO动作。 为此,首先需要定义IO操作是什么。 考虑一个IO动作的一种方式是它只是一个不带任何参数的函数。 例如:

 // log :: a -> IO b function log(x) { return function () { // IO action return console.log(x); }; } 

将IO动作表示为不带参数的函数的一个优点是对于thunk ( 未评估的expression式 )来说,它是相同的表示forms 。 Thunk是那些能够在Haskell这样的语言中进行懒惰评估的东西。 因此,你得到懒惰的免费。

现在组成。 你如何在JavaScript中编写两个IO动作? 在Haskell中,您使用>>操作符来对IO操作进行sorting,通常按>>= (aka bind )来定义,如下所示:

 (>>=) :: Monad m => ma -> (a -> mb) -> mb (>>) :: Monad m => ma -> mb -> mb x >> y = x >>= \_ -> y 

在JavaScript中为IO操作编写等效的bind函数是很容易的:

 // bind :: IO a -> (a -> IO b) -> IO b function bind(x, y) { return function () { return y(x())(); }; } 

假设你有一个IO动作x :: IO a 。 因为它只是一个没有参数的函数,所以当你调用它的时候就相当于评估IO动作。 因此x() :: a 。 将此结果馈送给函数y :: a -> IO b导致IO操作y(x()) :: IO b 。 请注意,整个操作被包裹在一个多余的懒惰function。

同样,实现>>运算符也是一样简单。 我们把它叫做“序列”中的seq

 // seq :: IO a -> IO b -> IO b function seq(x, y) { return function () { return x(), y(); }; } 

这里我们评估IOexpression式x ,不关心它的结果,然后返回IOexpression式y 。 这正是>>运算符在Haskell中所做的。 请注意,整个操作被包裹在一个多余的懒惰function。

Haskell也有一个return函数,它将一个值提升到一个单一的上下文中。 由于return是JavaScript中的关键字,因此我们将其称为unit

 // unit :: a -> IO a function unit(x) { return function () { return x; }; } 

事实certificate,Haskell中还有一个sequence运算符,它在一个列表中对monadic值进行sorting。 它可以在IO操作的JavaScript中实现,如下所示:

 // sequence :: [IO a] -> IO [a] function sequence(array) { return function () { var list = array; var length = list.length; var result = new Array(length); var index = 0; while (index < length) result[index] = list[index++](); return result; }; } 

这就是我们需要的。 现在我们可以写:

 var world = sequence([log("1"), log("2"), log("3"), log("4")]); world(); // 1 // 2 // 3 // 4 

希望有所帮助。


是的,使用你的语法链接IO操作的确是可能的。 但是,我们需要重新定义一个IO操作是什么:

 function action(x) { return function (y) { return y ? action(seq(x, y)) : x(); }; } 

让我们通过一个例子来理解action函数的action

 // log :: a -> IO b // log :: a -> IO r -> IO r function log(x) { return action(function () { return console.log(x); }); } 

现在你可以做:

 log("1")(); // :: b log("1")(log("2")); // :: IO r 

在第一种情况下,我们评估IO操作log("1") 。 在第二种情况下,我们对IO操作log("1")log("2")sorting。

这可以让你做到:

 var world = (log("1"))(log("2"))(log("3"))(log("4")); world(); // 1 // 2 // 3 // 4 

另外你也可以这样做:

 var newWorld = (world)(log("5")); newWorld(); // 1 // 2 // 3 // 4 // 5 

等等….

其他一切都保持不变。 请注意,这在Haskell中是不可能的,因为一个函数不能返回两个结果。 另外,在我看来,它看起来很丑。 我宁愿使用sequence 。 但是,这是你想要的。

让我们看看这里发生了什么:

 var log = function(args) { var f0 = function() { return console.log(args); }; return function(f1) { return function() { f0(); return f1; }; }; }; 

并内联一点:

 var log = function(args) { return function(f1) { return function() { console.log(args); return f1; }; }; }; 

所以我们返回一个函数f ,它接受函数f1 ,并返回一个函数g ,它执行逻辑并返回f1 。 真是一口! 你的问题是为什么

 (log('1'))(log('2'))(log('3')); 

日志1 我把log('4')去掉了,因为去3就足以显示你描述的情况。 为了回答这个问题,让我们玩编译器,并进行内联游戏!

 (log('1'))(log('2'))(log('3')) // => ( function (f1) { return function () { console.log('1'); return f1; } } )( function (f1) { return function () { console.log('2'); return f1; } } )( function (f1) { return function () { console.log('3'); return f1; } } ) 

简单的替代。 我把每个log(something)实例,用函数的内容replace它,用传递的值replace参数。 让我们再来一次!

 ( function () { console.log('1'); return function (f1) { return function () { console.log('2'); return f1; } }; } )( function (f1) { return function () { console.log('3'); return f1; } } ) 

这一个有点棘手,我要扩展第一个函数调用。 最上面的函数接收到一个我们刚刚提供了一个值的参数f1 ,所以我进入了函数,并用给定值( log('2')的结果)replace了每个f1出现,就像使用log参数一样。

如果你还没有关注,看看这里发生了什么,但是我的build议是自己做的:把代码片段复制到你最喜欢的代码编辑器中,然后自己做扩展。

现在你可以看到为什么log('1')被调用了。 编译器需要做的下一件事情就是处理下一个函数调用。 而且whadya知道,那个函数的第一行是console.log ! 最好做!

我们可以做什么!?

我不认识Haskell或者IO Monad,但是按照你现在的计划,我不认为你可以用基本的function来做你想做的事情,而不是像那样。 如果你能说出你想用这个… erm模式解决什么问题,也许我们可以帮忙!

执行时

 var world = (log('1'))(log('2'))(log('3'))(log('4')); 

(log('1'))首先被执行,返回一个函数(log('2'))。

这个匿名函数开始执行,但不接受任何参数。 日志('3')被忽略。 这可以通过validation

 if(typeof(arguments[0]) == 'function'){ console.log("Got a neglected argument"); console.log(arguments[0]()); } 

执行f0(); (打印1到屏幕),我们返回指向由log('2')返回的函数的f1,这取决于log('4');

这可以通过执行来validation: world()()()

这个输出:

 2 4 undefined 

这是因为你只是返回并返回一切…

在输出中有三件事情打印出来:

 1 function () { f0(); return f1; } 2 

1)第一个输出:1

这是因为: console.log(args)只能在你的链接中执行一次,因为f0只能在最后一次执行一次,因为它发现args是1(因为返回每个嵌套函数,最后返回的值是当args的值为1时执行f0()的函数f1,然后打印1到控制台。

2)秒输出函数f1

return f1; (当你传递args为1的时候,它返回给函数)在最后的返回执行

  function () { f0(); return f1; } 

回到variables世界,因此只有内部的嵌套函数被打印到控制台。

3)第三个输出:2

那么当你执行函数world()

同样,函数f1直接执行(请参阅worldworld()之间的差别),但这次是将args传递为2函数。

原因:world只输出函数, world()会执行函数。
当你写world()时,在function f1返回的最后一次,args的值是2,直接执行。

我知道我有非常措辞的答案..但希望这有助于(希望你明白)