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直接执行(请参阅world
和world()
之间的差别),但这次是将args
传递为2
函数。
原因:world只输出函数, world()
会执行函数。
当你写world()
时,在function f1
返回的最后一次,args的值是2,直接执行。
我知道我有非常措辞的答案..但希望这有助于(希望你明白)