F# 可变函数参数

16

有没有一种方法可以在F#中使用可变函数参数,从而允许类似以下的操作:

let mutable i = 9

let somefun n = n <- 12; ()

somefun i

(* *not* a real-world example *)

我理解可以通过将其包装成记录类型来使其工作

type SomeRec = { mutable i: int }

let ri = { i = 9 }

let someotherfun r = r.i <- 12; ()

我发现可以用类似的方法处理类成员,但是即使我浏览了整个 F# 语言规范(没错,我真的看了),也没有找到允许第一种情况的语法,编译器对我尝试这样做非常不满。我本来希望能有某种类型注释,但是可变不能在这种情况下使用。

我知道我本来不应该这样做的,但第一种情况(int 绑定)和第二种情况(record类型)在语义上是相同的,任何这样的反对理由都同样适用于两种情况。

所以我认为我在这里漏掉了什么。


8
如果您需要改变参数的状态,那么您仍然在进行命令式的思考。您能否准确描述您要做什么,也许有人可以建议更符合惯用语的解决方案。 - Juliet
2个回答

24
你可以使用ref作为参数。
let v = ref 0
let mutate r = 
    r := 100
mutate v
printfn "%d" !v

或者使用 ByRef 关键字

let mutable v = 0
let mutate (r : byref<_>) = 
    r <- 100
mutate &v
printfn "%d" v

5
请注意,byref 类似于 C# 的 ref。如果您需要 C# 的 out,那么请使用 byref,但同时将 [<System.Runtime.InteropServices.Out>] 属性添加到参数中。 - Brian
4
这个答案从技术上讲是正确的,但如果在实践中使用会让我感到不舒服。原帖作者应该坚持使用F#的习惯用法,而不是尝试以稍微不同的语法编写C#代码。 - Juliet
7
@Juliet 这比在F#中的功能等效方式快得多。我已经在生产代码中使用过它。 - J D
@JD @Julient - 看起来如果你要从C#调用F#并使用[<Out>]可变结果类型,就需要使用byref<..>,如此处所示:https://musingstudio.com/2017/02/17/how-to-extend-f-discriminated-unions-for-use-from-c/comment-page-1/?unapproved=14947&moderation-hash=e7e536aee0cec658f39a04dfc3d2e934#comment-14947希望能学到更多F#风格的从C# v7.0.3 (.NET 2)调用F#的方法。谢谢。 - rfreytag

13
使用 byref 关键字,它等同于 C# 的 ref 关键字。 请参见通过引用传递

1
哦,亲爱的,我还缺少一些非常基本的部分。我想我得重新阅读整个东西再次。很抱歉,我只能标记一个“已接受”的答案,但会投票支持这个答案。 - Alexander Rautenberg
2
我刚刚在另一个主题中发现了Jon Skeet关于参数传递的文章:http://www.yoda.arachsys.com/csharp/parameters.html。虽然这是关于C#的,但这正是你现在需要的。 - Artem Koshelev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接