JavaScript 函数通过链式组合

2024-01-05

我检查了重复问题的可能性, 并且无法找到准确的解决方案。

我用 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

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

Thanks.

这个问题已经解决了,但是还有更进一步的问题

异步问题如评论讨论所示

当我们有

// 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;
}));

Now,

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

到目前为止一切顺利,现在我们尝试使用bind

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();

多个返回值。

我用谷歌搜索并在这里搜索,但找不到答案。

这是什么??

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

Thanks!


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

// log :: a -> IO b

function log(x) {
    return function () {       // IO action
        return console.log(x);
    };
}

将 IO 操作表示为不带参数的函数的优点之一是,它与thunks https://stackoverflow.com/a/21441278/783743 (未计算的表达式 https://stackoverflow.com/a/19862784/783743)。 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

很容易写出等价的bindJavaScript 中 IO 操作的函数:

// 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 bIO 操作的结果y(x()) :: IO b。请注意,为了懒惰,整个操作都包装在一个多余的函数中。

同样,实现也同样简单>>操作员。我们就这样称呼它吧seq如“顺序”。

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

function seq(x, y) {
    return function () {
        return x(), y();
    };
}

这里我们评估 IO 表达式x,不关心其结果然后返回IO表达式y。这正是>>运算符在 Haskell 中执行。请注意,为了懒惰,整个操作都包装在一个多余的函数中。

哈斯克尔还有一个return将值提升到一元上下文的函数。自从return是 JavaScript 中的一个关键字,我们称之为unit反而:

// unit :: a -> IO a

function unit(x) {
    return function () {
        return x;
    };
}

事实证明还有一个sequenceHaskell 中的运算符对列表中的单值进行排序。它可以在 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;
    };
}

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

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函数确实使用了一个例子:

// 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") and log("2").

这允许您执行以下操作:

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反而。然而,这就是你想要的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JavaScript 函数通过链式组合 的相关文章

随机推荐