hap*_*pyD 4 f# functional-programming
我在向类中添加递归函数时遇到了麻烦.
我可以使用let声明函数私有没有问题在我的成员声明之上.
但是当我尝试使用成员公开它时,它不会编译.
member this.rec mux xs ys =
match xs with
| [] -> ys
| x::xt -> x :: mux ys xt
Run Code Online (Sandbox Code Playgroud)
感谢您纠正我,并指导我在线提供适当的资源.我一直在阅读很多教程,但我找不到这个信息.
成员函数总是递归的,不需要rec关键字:
member this.mux xs ys =
Run Code Online (Sandbox Code Playgroud)
(即使有一个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
Run Code Online (Sandbox Code Playgroud)
(回应评论)
let绑定功能可以隐藏先前定义的标识符.例如:
let f x = x+5
let f x = x-2
let a = f 5 // a = 3, not 10
Run Code Online (Sandbox Code Playgroud)
这是完全合法的事情(模块中的顶级除外),并且经常用于实用目的,例如消毒参数:
let sendEmail email subject body =
let email = canonicalize email
...
Run Code Online (Sandbox Code Playgroud)
请注意,在这个函数中,我做的第一件事是清理电子邮件,然后继续做任何事情(注意:这不是为参数"赋值"新值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"
Run Code Online (Sandbox Code Playgroud)
在这个例子中,我sendEmail用一个新的定义"遮蔽"了这个函数,该定义在调用原始文件之前记录了用户的名字sendEmail.如果我将"new"定义sendEmail为递归(即let rec sendEmail name = ...),则此程序将导致无限循环:函数将无限地调用自身.但是因为函数不是递归的,所以它能够引用先前定义的同名值.
成员函数没有这个问题:你不能遮蔽一个类方法,那将毫无意义.
在不同语言中以不同方式解决该问题.
例如,在默认情况下一切都可变的语言中,根本不会出现这个问题:你只是改变了值,就是这样......除非你想改变类型,否则你就搞砸了.
再举一个例子,在Haskell中,所有值都是递归的,而阴影会引发警告.结果,人们被迫使用刻度线或通过命名获得创造性,甚至引入不需要的monad.