是否可以在SML中编写递归匿名函数?我知道我可以使用fun
语法,但我很好奇。
我写过,作为我想要的一个例子:
val fact =
fn n => case n of
0 => 1
| x => x * fact (n - 1)
答案 0 :(得分:14)
将匿名函数绑定到a时,匿名函数不再是匿名函数
变量。由于val rec
只是fun
的派生形式而没有
除了外观之外的差异,您也可以使用它来编写它
fun
语法。您也可以在fn
表达式中进行模式匹配
与case
中一样,因为案例来自fn
。
所以简单来说,你可以把你的功能写成
val rec fact = fn 0 => 1
| x => x * fact (x - 1)
但这与下面更具可读性(在我的意见中)完全相同
fun fact 0 = 1
| fact x = x * fact (x - 1)
据我所知,使用编写代码只有一个原因
long val rec
,这是因为您可以更轻松地使用代码注释代码
评论和强制类型。例如,如果您之前和之前已经看过Haskell代码
就像他们键入注释函数的方式一样,你可以写一些东西
像这样
val rec fact : int -> int =
fn 0 => 1
| x => x * fact (x - 1)
正如templatetypedef所提到的,可以使用定点来完成它 组合子。这样的组合器可能看起来像
fun Y f =
let
exception BlackHole
val r = ref (fn _ => raise BlackHole)
fun a x = !r x
fun ta f = (r := f ; f)
in
ta (f a)
end
然后您可以使用以下代码计算fact 5
,该代码使用匿名
函数表达教师功能,然后绑定结果
计算到res
。
val res =
Y (fn fact =>
fn 0 => 1
| n => n * fact (n - 1)
)
5
定点代码和示例计算由MortenBrøns-Pedersen提供。
在我所知的语言中,递归函数总是绑定到a 名称。方便和传统的方式由关键字提供 “定义”,或“让”,或“letrec”,......
根据定义,这是真实的。如果函数(递归与否)未绑定到名称,则它将是匿名的。
非常规,更匿名的方式是通过lambda绑定。
我没有看到匿名函数有什么非常规的,它们一直在SML中使用,实际上是在任何函数式语言中。它甚至开始出现在越来越多的命令式语言中。
Jesper Reenberg的回答显示了lambda绑定; “匿名” 函数被lambdas绑定到名称“f”和“fact”(称为 SML中的“fn”。
匿名函数实际上是匿名的(不是“匿名” - 没有引号),是的当然它会被绑定在范围中作为参数传递给它的函数。在任何其他情况下,语言将完全无用。调用map (fn x => x) [.....]
时会发生完全相同的事情,在这种情况下,匿名身份函数仍然是匿名的。
匿名函数的“正常”定义(至少根据wikipedia),说它不能绑定到标识符,有点弱,应该包含“当前的隐含语句”环境”。
事实上,对于我的示例来说,这是正确的,就像在仅包含fun Y ...
和val res ..
val Y: (('a -> 'b) -> 'a -> 'b) -> 'a -> 'b
val res: int32
从中可以看出,环境中没有绑定任何匿名函数。
较短的“lambdanonymous”替代品,需要OCaml推出 通过“ocaml -rectypes”:
(fun f n -> f f n) (fun f n -> if n = 0 then 1 else n * (f f (n - 1)) 7;; Which produces 7! = 5040.
您似乎完全误解了原始问题的想法:
是否可以在SML中编写递归匿名函数?
简单的答案是肯定的。复杂的答案是(除其他外?)使用定点组合器完成此操作的一个例子,而不是“lambdanonymous”(这应该是什么意思)的示例在另一种语言中使用SML中甚至远程可能的功能完成。
答案 1 :(得分:8)
您只需将rec
放在val
之后,就像在
val rec fact =
fn n => case n of
0 => 1
| x => x * fact (n - 1)
Wikipedia在第一部分的顶部附近描述了这一点。
答案 2 :(得分:2)
let fun fact 0 = 1
| fact x = x * fact (x - 1)
in
fact
end
这是一个递归匿名函数。名称'fact'仅在内部使用。
某些语言(例如Coq)使用“fix”作为递归函数的原语,而某些语言(例如SML)使用recursive-let作为原语。这两个原语可以互相编码:
fix f => e
:= let rec f = e in f end
let rec f = e ... in ... end
:= let f = fix f => e ... in ... end
答案 3 :(得分:-1)
在我所知的语言中,递归函数将始终绑定到名称。方便和传统的方式由“定义”,“让”或“letrec”等关键字提供......
非传统的,更加匿名的寻找方式是通过lambda绑定。 Jesper Reenberg的答案显示了lambda绑定; “匿名”函数通过lambdas绑定到名称“f”和“fact”(在SML中称为“fn”)。
较短的“lambdanonymous”替代方案,需要OCaml由“ocaml -rectypes”发起:
(fun f n -> f f n)
(fun f n -> if n = 0 then 1 else n * (f f (n - 1))
7;;
哪个产生7个! = 5040。