Javascript 这是不动点组合器的实现吗?

Javascript 这是不动点组合器的实现吗?,javascript,functional-programming,monads,combinators,Javascript,Functional Programming,Monads,Combinators,我认为这不能称为“定点递归”,因为它太简单了。然而,我最近意识到它实际上可能是 我是否有效地实现了定点递归 下面是有问题的函数: /* recursive kleisli fold */ var until = function(f) { return function(a) { return kleisli(f, until(f))(a); }; }; 下面是一些额外的上下文: // The error monad's bind var bind_ = fun

我认为这不能称为“定点递归”,因为它太简单了。然而,我最近意识到它实际上可能是

我是否有效地实现了定点递归

下面是有问题的函数:

/* recursive kleisli fold */
var until = function(f) {
    return function(a) {
        return kleisli(f, until(f))(a);
    };
};
下面是一些额外的上下文:

// The error monad's bind
var bind_ = function(f, m) { return m.m === Success ? f(m.a) : m; };

var bind = function(f, m) {
    return m !== undefined && m.m !== undefined && m.a !== undefined ? bind_(f, m) : m;
};

var kleisli = function(f1, f2) { 
    return function(a) { 
        return bind(f2, f1(a)); 
    };
};

代码的其余部分是,但上面的代码片段应该足够了。

定点组合器的定义是一个函数
F
,它接受一个函数
F
,并返回一个函数
p

给定
F(F)=p
然后
p=F(p)

有许多可能的不动点组合,可以写。不要让直率让你认为某些东西不是定点组合;以下是JavaScript的标准定义,非常简单:

  var fix = function(f) {
       return function(x) { 
        return f(fix(f))(x)
      }
  };
然后可以使用以下方法计算阶乘的定点:

var fact = function(f) { 
              return function(n) { return (n == 0) ? 1 : (n * f(n - 1)) } 
           };

alert(fix(fact)(7)); // alerts us with 5040.
有关不同的定点组合器(Y组合器)的示例,请参阅

让我们看看你的
until
combinator是否计算固定点。由于您使用的是一元函数,因此定点定义会略有变化,以处理一元结构,其中
F
是一个(一元)定点组合器

给定
F(F)=p
然后
p=F*。p

其中
f*。p
表示函数
p
与函数
f
的Kleisli组合(在您的代码中,您可以将此
Kleisli(p,f)
,您可以将
*
视为
bind
)。我将使用这个符号,因为它比编写JavaScript要短

让我们展开
的定义,直到
,然后看看我们得到了什么:

until(f) = (until(f))* . f 
         = (until(f)* . f)* . f 
         = ((... . f)* . f)* . f
         = ... . f* . f* . f     (associativity of bind for a monad: (g* . f)* = g* . f*)
         = p 
是否
p=f*。p

... . f* . f* . f  =?=  f* . ... . f* . f* . f
是的,我想是的。虽然我不认为这是一个有用的固定点。(恐怕我还没有一个很好的论据来证明这一点——但我认为这基本上是一个最大的固定点,只会产生分歧)

对我来说,它看起来像是
kleisli
的参数,直到
应该被交换。也就是说,我们希望在
fix
示例中执行与Kleisli等效的应用程序,因此我们需要将递归调用
的一元结果传递到(f)
f

  var until = function(f) {
      return function(a) {
          return kleisli(until(f), f)(a);
      };
  };
让我们展开
的这个新定义,直到

until(f) = f* . until(f)
         = f* . (f* . until(f))
         = f* . f* . ...
         = p 
是否
p=f*。p
?是的,它有:

f* . f* ... = f* . (f* . f* . ...)
因为在f*合成的无限链上再加上一个f*合成是同一个函数

使用您的
kleisli
函数时,我遇到了一些发散问题(一些计算发生得太快,因此计算一直运行到堆栈空间用完为止)。相反,以下几点似乎适合我:

 var until = function(f) {
     return function(a) {
        return bind(f,until(f)(a));
    };
 };

有关一元代码的固定点的更多信息,您可能想查看

p在实际实现中使用;我用它作为一个谓词,将退出条件放在组合子中,而不是放在正在修复的函数中。为了清晰起见,我删除了它,因为我的问题是关于我构建它的方式,而不管退出条件如何;尽管有旁注,但如果一个定点组合器有退出条件,它仍然是一个定点组合器吗?同样有旁注,haskell中的“error monad”要么是,而不是可能是:P@JimmyHoffa哦,对不起-我没有仔细阅读你的代码。希望我所写的仍然适用。在这种情况下,我可以删除最后一部分,因为它有点相切。为什么我要使用bind而不是kleisli?kleisli只是多余的,因为它已经在我返回kleisli的点上的函数中了吗?现在我的问题中删除了P;这是毫无意义的事实上,我应该删除它,当我删除退出条件