Recursion OCaml中的匿名递归函数

Recursion OCaml中的匿名递归函数,recursion,ocaml,anonymous-function,Recursion,Ocaml,Anonymous Function,如何制作匿名递归函数(一些简单的东西,例如阶乘n?)我听说这是可能的,但不知道如何在OCaml中工作 let a = fun x -> .... 我只是不知道如何保持下去…这里是一个仅使用匿名函数的阶乘定义: let fact = (fun f -> (fun x a -> f (x x) a) (fun x a -> f (x x) a)) (fun f n -> if n < 2 then 1 else n * f (n - 1))

如何制作匿名递归函数(一些简单的东西,例如阶乘n?)我听说这是可能的,但不知道如何在OCaml中工作

let a =
  fun x -> ....

我只是不知道如何保持下去…

这里是一个仅使用匿名函数的阶乘定义:

let fact =
    (fun f -> (fun x a -> f (x x) a) (fun x a -> f (x x) a))
    (fun f n -> if n < 2 then 1 else n * f (n - 1))
通过在这里查找Y组合符,我有点作弊:

更新

免责声明:你最好阅读lambda微积分、不动点和Y组合运算,而不是从我这里得到你的信息。我不是理论家,只是一个谦逊的实践者

按照实际计算几乎是不可能的(但我相信绝对值得这样做)。但在高层次上,这些想法是这样的

定义的第一行是Y组合符,它通常计算函数的不动点。递归函数恰好是函数之间的不动点

第一个目标是找到不动点是阶乘函数的函数。这是定义的第二行。如果给它一个类型为
int->int
的函数,它将返回另一个类型为
int->int
的函数。如果你给它阶乘函数,它会还给你阶乘函数。这意味着阶乘函数是它的不动点


那么,当你把Y组合符应用到这个函数上时,你确实得到了阶乘函数。

让我试着扩展一下Jeffrey Scofield的答案。阶乘函数的非匿名递归定义可以是

let rec fact n =
    if n < 2 then 1 else n * fact (n - 1)
此术语没有类型,因为“临时名称”
f
未绑定。但我们也可以通过边界
f
将其转化为一个具有类型的值。让我们调用结果
g

let g = fun f n -> if n < 2 then 1 else n * f (n - 1)
在本例中,类型变量由
(int->int)
实例化。 定义
y
的一种可能方法是

let y = fun g -> (fun x -> g (x x)) (fun x -> g (x x))
但这只适用于惰性评估(我相信Haskell已经做到了这一点)。由于OCaml具有急切求值功能,因此在使用时会产生堆栈溢出。原因是OCaml试图将类似于
yg8
的内容转换为

g (y g) 8
g (g (y g)) 8
g (g (g (y g))) 8
...
从未打过电话给
g
。 解决方案是在
y
中使用延迟计算:

let y = fun g -> (fun x a -> g (x x) a) (fun x a -> g (x x) a)
一个缺点是
y
不再适用于任意类型。它只适用于函数类型

y : ((`b -> `c) -> (`b -> `c)) -> (`b -> `c)
但您要求的是函数的递归定义,而不是其他值的递归定义。因此,我们对阶乘函数的定义是
yg
,其中
y
g
的定义如上所述。
y
g
都不是匿名的,但是可以很容易地进行补救:

(fun g -> (fun x a -> g (x x) a) (fun x a -> g (x x) a))
    (fun f n -> if n < 2 then 1 else n * f (n - 1))
(fungg->(funxa->g(xx)a)(funxa->g(xx)a))
(乐趣fn->如果n<2,则1其他n*f(n-1))
更新:

定义
y
仅适用于
-rectypes
选项。原因是我们将
x
应用于自身。

还有一种“直观”的方法来完成匿名递归,而无需求助于Y组合符

它使用let绑定来存储接受自身作为参数的lambda的值,这样它就可以使用自身作为第一个参数来调用自身,如下所示:

let fact = (let fact0 = (fun self n -> if n < 2 then 1 else n * self self (n - 1)) in (fun n -> fact0 fact0 n));;
let fact=(let fact0=(fun-self n->如果n<2,那么在(fun-n->fact0-fact0 n))中有1个else n*self(n-1));;

它是匿名的,只是因为它没有定义为
let rec

我已经修改了我的答案,但这是一个很大的主题。我只知道一小部分。@JeffreyScofield您可以通过定义类似于
type t=t of t->t
的内容来避免使用
-rectypes
。喜欢你的答案。是的,这在上面链接的Y Combinator页面上有解释。谢谢
y : ((`b -> `c) -> (`b -> `c)) -> (`b -> `c)
(fun g -> (fun x a -> g (x x) a) (fun x a -> g (x x) a))
    (fun f n -> if n < 2 then 1 else n * f (n - 1))
let fact = (let fact0 = (fun self n -> if n < 2 then 1 else n * self self (n - 1)) in (fun n -> fact0 fact0 n));;