gpt4 book ai didi

f# - 将递归函数作为成员添加到类

转载 作者:行者123 更新时间:2023-12-04 23:39:36 26 4
gpt4 key购买 nike

我在向类中添加递归函数时遇到问题。

我可以使用 let 在我的成员声明之上声明函数私有(private)没有问题。

但是当我尝试使用成员将其公开时,它不会编译。

member this.rec mux xs ys =
match xs with
| [] -> ys
| x::xt -> x :: mux ys xt

感谢您纠正我并指出我正确的在线资源。我一直在阅读很多教程,但我找不到这个信息。

最佳答案

成员函数总是递归的,没有 rec需要关键字:

member this.mux xs ys =

(即使有 rec 关键字,它也会出现在 this 之前,与 private - member rec this.mux ... 相同)

但是,一旦您将其声明为成员,您也必须将其引用为成员 - 即 this.mux而不是 mux :
member this.mux xs ys =
match xs with
| [] -> ys
| x::xt -> x :: this.mux ys xt

为什么成员函数总是递归的,而 let-bound 函数不是

(回应评论)
let -bound 函数可以隐藏先前定义的标识符。例如:
let f x = x+5
let f x = x-2
let a = f 5 // a = 3, not 10

这是一件完全合法的事情(除了在模块的顶层),并且经常用于实用目的,例如 sanitizer 参数:
let sendEmail email subject body =
let email = canonicalize email
...

请注意,在这个函数中,我做的第一件事是清理电子邮件,然后继续做任何事情(注意:这不是为参数“分配”新值 email,而是定义一个恰好发生在具有相同的名称)。
email 的新定义用于函数的其余部分而不是原始参数 email .这称为“阴影”。

现在,请注意 email 的新定义引用 email 的旧定义.这只是可能的,因为 email不是递归的:编译器知道 email 这个词在 email 的定义内指的是先前定义的值,而不是现在定义的值。

“但是等等”——你说——“ email 递归意味着什么?难道“递归”这个词只适用于函数吗?”。嗯,不。值也可以是递归的,但这是另一个话题。现在,这里有一个不同的例子:
let notifyUsers sendEmail log =
let sendEmail name =
log ("Notifying " + name)
sendEmail (name + "@contoso.com")

sendEmail "John"
sendEmail "Mark"
sendEmail "Matthew"
sendEmail "Luke"

在这个例子中,我“隐藏”了函数 sendEmail在调用原始 sendEmail 之前记录用户名称的新定义.如果我定义了我的"new" sendEmail作为递归(即 let rec sendEmail name = ... ),该程序将导致无限循环:该函数将无休止地调用自身。但由于该函数不是递归的,它能够引用先前定义的同名值。

成员函数没有这个问题:你不能影子一个类方法,那是没有意义的。

这个问题在不同的语言中有不同的解决方法。
例如,在默认情况下所有内容都可变的语言中,根本不会出现这个问题:你只是改变了值,就是这样......除非你也想改变类型——那么你就完蛋了。
再举一个例子,在 Haskell 中,所有的值都是递归的,阴影会导致警告。结果,人们被迫 use ticks或者在命名方面发挥创意,甚至在不需要的地方引入一个 monad。

关于f# - 将递归函数作为成员添加到类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42074884/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com