Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/security/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Recursion SML中的递归匿名函数_Recursion_Functional Programming_Anonymous Function_Sml - Fatal编程技术网

Recursion SML中的递归匿名函数

Recursion SML中的递归匿名函数,recursion,functional-programming,anonymous-function,sml,Recursion,Functional Programming,Anonymous Function,Sml,可以在SML中编写递归匿名函数吗?我知道我可以用fun语法,但我很好奇 作为我想要的一个例子,我写了: val fact = fn n => case n of 0 => 1 | x => x * fact (n - 1) 您只需将rec放在val之后,如中所示 val rec fact = fn n => case n of 0 =>

可以在SML中编写递归匿名函数吗?我知道我可以用
fun
语法,但我很好奇

作为我想要的一个例子,我写了:

val fact =
    fn n => case n of
                 0 => 1
               | x => x * fact (n - 1)

您只需将
rec
放在
val
之后,如中所示

val rec fact =
        fn n => case n of
                     0 => 1
                   | x => x * fact (n - 1)

在第一节顶部附近介绍了这一点。

当您将匿名函数绑定到 变量因为
val rec
只是
fun
的派生形式,没有 除了外观上的不同,你还可以用
fun
语法。您还可以在
fn
表达式中进行模式匹配 如
案例
,案例源自
fn

因此,简单地说,您可以将函数编写为

val rec fact = fn 0 => 1
                | 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                       
定点代码和示例计算由Morten Brøns Pedersen提供


对George Kangas回答的最新回应:
在我所知道的语言中,递归函数总是绑定到 名称方便和常规的方法是通过关键字提供的,如 “定义”或“let”或“letrec”

从定义上来说,这是微不足道的事实。如果函数(递归或非递归)没有绑定到名称,那么它将是匿名的

非传统的、更匿名的方式是lambda绑定

我看不出匿名函数有什么不寻常的地方,它们一直在SML中使用,事实上在任何函数语言中都是如此。它甚至开始出现在越来越多的命令式语言中

Jesper Reenberg的回答显示了lambda绑定;“匿名者” 函数通过lambdas(调用 SML中的“fn”)

匿名函数实际上是匿名的(不是“匿名的”--没有引号),是的,它当然会被绑定在作为参数传递到的任何函数的范围内。在任何其他情况下,这种语言都是毫无用处的。调用
map(fnx=>x)[…]
时也会发生同样的情况,在本例中,匿名标识函数实际上仍然是匿名的

匿名函数的“正常”定义(至少根据)表示它不能绑定到标识符,这有点弱,应该包含“在当前环境中”的隐式语句

事实上,对于我的示例来说,这是正确的,在一个仅包含
funy…
val res…

val Y: (('a -> 'b) -> 'a -> 'b) -> 'a -> 'b
val res: int32
由此可以看出,环境中没有绑定任何匿名函数

较短的“lambdanonymous”替代方案,需要启动OCaml 通过“ocaml-矩形”:

你似乎完全误解了原来问题的意思:

可以在SML中编写递归匿名函数吗


答案很简单,是的。复杂的答案是(除其他外?)一个使用定点组合器的例子,而不是一个“lambdanonymous”(什么意思)的例子,在另一种语言中使用SML中甚至不可能实现的功能。在我知道的语言中,递归函数总是绑定到一个名称。“定义”或“let”或“letrec”等关键字提供了方便而常规的方法

非传统的、更匿名的方式是lambda绑定。Jesper Reenberg的回答显示了lambda绑定;“匿名”函数通过lambdas(在SML中称为“fn”)绑定到名称“f”和“fact”

一个较短的“lambdanonymous”替代方案,需要由“OCaml-rectypes”启动OCaml:

哪个生产7个!=5040

let fun fact 0 = 1
      | fact x = x * fact (x - 1)
in
  fact
end
这是一个递归匿名函数。“事实”这个名称只在内部使用

有些语言(如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 

我不是ML方面的专家,但您可能正在寻找涉及定点组合器的东西,如Y组合器,这是从匿名函数构建递归函数的典型方法。@templatetypedef只要您不想使用匿名函数,您就是正确的(请记住,原来的问题不使用匿名函数),但是这不是一种很好的方法。请参阅我答案的最后一部分以获取示例:)明白了。我想维基百科没有这些信息,所以我到处找,除了那里。谢谢。非常感谢!:)你真是个救命恩人!:)你读过密码了吗?用OCaml示例回答这个问题并没有给原始问题带来价值,特别是当使用SML没有的递归类型时。总而言之,除了陈述一些已经知道的事实,我看不出你文章的意义。查看我的最新帖子。“[…]因为val rec只是乐趣的衍生形式[…]”:这不是相反吗?不。也许我们的意思是一样的,但从两个不同的角度来看
val rec
是核心语言的一部分,而
fun
关键字是派生形式。我不知道
(fun f n -> f f n)
(fun f n -> if n = 0 then 1 else n * (f f (n - 1))
7;;
let fun fact 0 = 1
      | fact x = x * fact (x - 1)
in
  fact
end
fix f => e   
  := let rec f = e in f end

let rec f = e ... in ... end 
  := let f = fix f => e ... in ... end