我检查了重复问题的可能性,但找不到确切的解决方案.
我在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
Run Code Online (Sandbox Code Playgroud)
我想做这个懒惰的评估.
或者撰写功能.
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
Run Code Online (Sandbox Code Playgroud)
有些事情是非常错误的.你能修好它吗?
谢谢.
当我们有
// 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();
}
}
});
Run Code Online (Sandbox Code Playgroud)
我们也常常非常想要异步连锁反应.
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;
}));
Run Code Online (Sandbox Code Playgroud)
现在,
world = (log(1))(async)(log(3));
//1
//3
//async process Done!
Run Code Online (Sandbox Code Playgroud)
到目前为止,顺利,现在我们尝试使用绑定
world = (log(1))
(bind((async), (log(x))));
//should be
//1
//async process Done!
//3
//in fact
//ReferenceError: x is not defined
Run Code Online (Sandbox Code Playgroud)
你可以修改一下吗?
retrun x, y;
多重价值的问题我不明白
// seq :: IO a -> IO b -> IO b
var seq = function(x, y)
{
return function()
{
return x(), y();
};
};
Run Code Online (Sandbox Code Playgroud)
正如图书馆作者所提到的那样
请注意,这在Haskell中是不可能的,因为一个函数不能返回两个结果.而且,在我的拙见中,它看起来很难看.
我同意,不知道这是什么
return x(), y();
多重回报值.
我在谷歌搜索并搜索,但找不到答案.
这是什么??
(以防万一,我会选择这个hack语法)
谢谢!
Aad*_*hah 26
因此,如果我正确理解了这个问题,您希望在JavaScript中链接IO操作.为此,首先需要定义IO操作的内容.想到IO动作的一种方法是它只是一个不带参数的函数.例如:
// log :: a -> IO b
function log(x) {
return function () { // IO action
return console.log(x);
};
}
Run Code Online (Sandbox Code Playgroud)
将IO操作表示为不带参数的函数的一个优点是它与thunk(未评估的表达式)的表示相同.Thunk是能够在像Haskell这样的语言中进行延迟评估的东西.因此,你可以免费得到懒惰.
现在组成.你如何在JavaScript中组成两个IO动作?在Haskell中,您使用>>
运算符对IO操作进行排序,这通常按>>=
(又名bind
)定义如下:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
(>>) :: Monad m => m a -> m b -> m b
x >> y = x >>= \_ -> y
Run Code Online (Sandbox Code Playgroud)
bind
在JavaScript中为IO操作编写等效函数很容易:
// bind :: IO a -> (a -> IO b) -> IO b
function bind(x, y) {
return function () {
return y(x())();
};
}
Run Code Online (Sandbox Code Playgroud)
假设你有一个IO动作x :: IO a
.因为它只是一个没有参数的函数,所以当你调用它时它等同于评估IO动作.因此x() :: a
.将此结果提供给函数会y :: a -> IO b
导致IO操作y(x()) :: IO b
.请注意,整个操作包含在多余的懒惰功能中.
同样,实现>>
运算符也是如此简单.我们将其seq
称为"序列".
// seq :: IO a -> IO b -> IO b
function seq(x, y) {
return function () {
return x(), y();
};
}
Run Code Online (Sandbox Code Playgroud)
这里我们评估IO表达式x
,不关心它的结果然后返回IO表达式y
.这正是>>
运营商在Haskell中的作用.请注意,整个操作包含在多余的懒惰功能中.
Haskell还具有将return
值提升为monadic上下文的函数.由于return
是JavaScript中的关键字,我们会将其称为unit
:
// unit :: a -> IO a
function unit(x) {
return function () {
return x;
};
}
Run Code Online (Sandbox Code Playgroud)
事实证明sequence
,Haskell中还有一个运算符,它在列表中对monadic值进行排序.它可以在JavaScript中实现,用于IO操作,如下所示:
// 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;
};
}
Run Code Online (Sandbox Code Playgroud)
这就是我们所需要的一切.现在我们可以写:
var world = sequence([log("1"), log("2"), log("3"), log("4")]);
world();
// 1
// 2
// 3
// 4
Run Code Online (Sandbox Code Playgroud)
希望有所帮助.
是的,确实可以使用您的语法链接IO操作.但是,我们需要重新定义IO操作的内容:
function action(x) {
return function (y) {
return y ? action(seq(x, y)) : x();
};
}
Run Code Online (Sandbox Code Playgroud)
让我们action
通过一个例子来理解函数的作用:
// log :: a -> IO b
// log :: a -> IO r -> IO r
function log(x) {
return action(function () {
return console.log(x);
});
}
Run Code Online (Sandbox Code Playgroud)
现在你可以这样做:
log("1")(); // :: b
log("1")(log("2")); // :: IO r
Run Code Online (Sandbox Code Playgroud)
在第一种情况下,我们评估了IO操作log("1")
.在第二种情况下,我们测序IO动作log("1")
和log("2")
.
这允许你这样做:
var world = (log("1"))(log("2"))(log("3"))(log("4"));
world();
// 1
// 2
// 3
// 4
Run Code Online (Sandbox Code Playgroud)
另外你还可以这样做:
var newWorld = (world)(log("5"));
newWorld();
// 1
// 2
// 3
// 4
// 5
Run Code Online (Sandbox Code Playgroud)
等等....
其他一切都是一样的.请注意,这在Haskell中是不可能的,因为一个函数不能返回两个结果.而且,在我的拙见中,它看起来很难看.我更喜欢使用sequence
.但是,这就是你想要的.
让我们来看看这里发生了什么:
var log = function(args)
{
var f0 = function()
{
return console.log(args);
};
return function(f1)
{
return function()
{
f0();
return f1;
};
};
};
Run Code Online (Sandbox Code Playgroud)
并且内联了一下:
var log = function(args) {
return function(f1) {
return function() {
console.log(args);
return f1;
};
};
};
Run Code Online (Sandbox Code Playgroud)
所以我们返回一个f
接受函数的函数f1
,并返回一个g
执行逻辑并返回的函数f1
.相当满口!你的问题是为什么
(log('1'))(log('2'))(log('3'));
Run Code Online (Sandbox Code Playgroud)
记录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;
}
}
)
Run Code Online (Sandbox Code Playgroud)
简单的替代.我拿了每个实例log(something)
,用函数的内容替换它,用传递的值替换参数.让我们再来一次!
(
function () {
console.log('1');
return function (f1) {
return function () {
console.log('2');
return f1;
}
};
}
)(
function (f1) {
return function () {
console.log('3');
return f1;
}
}
)
Run Code Online (Sandbox Code Playgroud)
这个有点棘手:我扩展了第一个函数调用.最上面的函数接收了一个f1
我们刚刚提供了一个值的参数,所以我进入函数并用f1
给定的值(结果log('2')
)替换了每个匹配项,就像log
参数一样.
如果你仍然不遵循,请再次查看此处发生的事情,但我的建议是自己动手:将代码段复制到您喜欢的代码编辑器中并自行进行扩展.
现在你可能会看到log('1')
被调用的原因.我们编译器需要做的下一件事就是处理下一个函数调用.而whadya知道,该功能的第一行是console.log
!做得更好!
我不知道Haskell或IO Monad,但按照你目前的计划,我认为你不能用基本功能做你想做的事情,而不是那样.如果你能用这个...呃......模式说出你想解决什么问题,也许我们可以提供帮助!
归档时间: |
|
查看次数: |
3740 次 |
最近记录: |