通过链接的JavaScript函数组合

通过链接的JavaScript函数组合,javascript,node.js,Javascript,Node.js,我已经检查了重复问题的可能性, 也找不到确切的答案 我用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 我想做这个懒惰的评估 或编写函数 var log = function

我已经检查了重复问题的可能性, 也找不到确切的答案

我用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
我想做这个懒惰的评估

或编写函数

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
有些事情很不对劲。 你能修好它吗

谢谢

这个问题已经解决了,但还有进一步的问题 注释讨论中显示的异步问题 当我们有

// 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();
    }
  }
});
我们也常常非常希望异步链式反应

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;
}));
到目前为止还很好,很平滑,现在我们尝试使用bind

world = (log(1))
  (bind((async), (log(x))));

//should be
//1
//async process Done!
//3

//in fact
//ReferenceError: x is not defined
请你修改一下以使它工作好吗

关于
retrunx,y的更多信息多值
我不明白

  // seq :: IO a -> IO b -> IO b
    var seq = function(x, y)
    {
      return function()
      {
        return x(), y();
      };
    };
正如图书馆作者所提到的

注意,这在Haskell中是不可能的,因为一个函数不能返回两个结果。而且,依我拙见,它看起来很丑

我同意,但不知道这是怎么回事

返回x(),y()

多重返回值

我在这里搜索,但找不到答案

这是什么

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


谢谢

这是因为您正在返回并返回所有内容

输出中打印了三个内容:

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

2
1) 第一次输出:1

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

2) 第二次输出函数f1

返回f1(将args作为1传递给函数时返回)

  function ()
            {
              f0();
              return f1;
            }
回到变量世界,因此只有内部嵌套函数被打印到控制台

3) 第三次产出:2

然后在执行函数
world()

同样,直接执行函数f1(请参见
world
world()
)之间的细微差别),但这一次是在您将
args
作为
2
传递时返回的函数

原因:world将只输出函数,
world()
将执行函数。
编写
world()
时,在上次返回
函数f1
时,直接执行args was 2的值


我知道我的回答措辞很糟糕。。但希望这有帮助(希望您理解)

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

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)
的每个实例,用函数的内容替换它,用传递的值替换参数。让我们再来一次

(
  function () {
    console.log('1');
    return function (f1) {
      return function () {
        console.log('2');
        return f1;
      }
    };
  }
)(
  function (f1) {
    return function () {
      console.log('3');
      return f1;
    }
  }
)
下面这个有点棘手:我扩展了第一个函数调用。最顶层的函数接收到一个参数
f1
,我们只为它提供了一个值,因此我进入该函数并用给定的值替换了
f1
的每一次出现(结果是
log('2')
),就像
log
参数一样

如果您仍然没有遵循,请再次查看此处发生的情况,但我的建议是自己执行:将代码段复制到您最喜欢的代码编辑器中,然后自己进行扩展

现在您可以了解调用
log('1')
的原因。我们编译器接下来需要做的就是处理下一个函数调用。你知道吗,该函数的第一行是一个
控制台.log
!最好去做

我们能做什么!?
我不知道Haskell或IO Monad,但正如你目前计划的那样,我认为你不能用基本功能做你想做的事情,不是那样的。如果你能说出你想用这个…呃…模式解决什么问题,也许我们能帮上忙

因此,如果我正确理解了这个问题,您希望在JavaScript中链接IO操作。为此,您首先需要定义IO操作是什么。理解IO操作的一种方式是,它只是一个不带参数的函数。例如:

// log :: a -> IO b

function log(x) {
    return function () {       // IO action
        return console.log(x);
    };
}
将IO操作表示为不带参数的函数的一个优点是,它与()的表示形式相同。Thunks是在Haskell这样的语言中支持惰性计算的东西。因此你可以免费得到懒惰

现在是作文。如何用JavaScript编写两个IO操作?在Haskell中,您使用
>
操作符对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;
    };
}
(>>=)::Monad m=>ma->(a->mb)->mb
(>>)::单子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
。请注意,整个操作都包含在一个多余的惰性函数中

类似地,实现
>
操作符也同样简单。让我们把它称为“序列”

// seq :: IO a -> IO b -> IO b

function seq(x, y) {
    return function () {
        return x(), y();
    };
}
这里我们计算IO表达式
x
,不关心其结果,然后返回IO表达式
y
。这正是歌剧院的风格
// unit :: a -> IO a

function unit(x) {
    return function () {
        return x;
    };
}
// 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
function action(x) {
    return function (y) {
        return y ? action(seq(x, y)) : x();
    };
}
// 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
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
var world = (log('1'))(log('2'))(log('3'))(log('4'));
if(typeof(arguments[0]) == 'function'){
    console.log("Got a neglected argument");
    console.log(arguments[0]());
}
2
4
undefined