这是一个非常简单的问题,我只是想检查一下我正在做什么,以及我如何解释F#是有道理的。如果我有陈述
let printRandom =
x = MyApplication.getRandom()
printfn "%d" x
x
而不是将printRandom
作为函数创建,F#运行一次,然后为其赋值。所以,现在,当我调用printRandom时,不是获取新的随机值并打印它,我只是得到第一次返回的内容。我可以解决这个问题:
let printRandom() =
x = MyApplication.getRandom()
printfn "%d" x
x
这是在无参数函数和值之间进行区分的正确方法吗?这对我来说似乎不太理想。是否会对咖喱,成分等产生影响?
答案 0 :(得分:19)
正确看待这种情况的方法是F#没有无参数函数。所有函数都必须带一个参数,但有时你不关心它是什么,所以你使用()
(单位类型的单例值)。你也可以做这样的函数:
let printRandom unused =
x = MyApplication.getRandom()
printfn "%d" x
x
或者这个:
let printRandom _ =
x = MyApplication.getRandom()
printfn "%d" x
x
但()
是表示不使用参数的默认方式。它向调用者表达了这一事实,因为类型为unit -> int
而不是'a -> int
;以及读者,因为呼叫网站是printRandom ()
而不是printRandom "unused"
。
实际上,currying和compos确实依赖于所有函数都接受一个参数并返回一个值的事实。
顺便说一下,使用unit编写调用的最常用方法是使用空格,特别是在F#的非.NET亲属中,如Caml,SML和Haskell。这是因为()
是一个单例值,而不是像C#中的语法一样。
答案 1 :(得分:8)
您的分析是正确的。
第一个实例定义一个值而不是一个函数。我承认当我开始使用F#时,这几次抓到了我。来自C#,包含多个语句的赋值表达式必须是lambda并因此延迟求值似乎很自然。
在F#中情况并非如此。语句几乎可以任意嵌套(并且它具有局部范围的函数和值)。一旦你对此感到满意,你就会开始将它视为一个优势,因为你可以创建函数的其余部分无法访问的函数和延续。
第二种方法是创建逻辑上不带参数的函数的标准方法。我不知道F#团队用于此声明的精确术语(可能是一个函数采用unit
类型的单个参数)。所以我无法评论它会如何影响currying。
答案 2 :(得分:7)
这是绘制它的正确方法吗? 参数之间的区别 功能和价值观?这似乎少了 比我理想。它有吗? 在结论,成分, 等?
是的,你所描述的是正确的。
为了它的价值,它有一个非常有趣的结果,能够部分评估声明中的函数。比较这两个函数:
// val contains : string -> bool
let contains =
let people = set ["Juliet"; "Joe"; "Bob"; "Jack"]
fun person -> people.Contains(person)
// val contains2 : string -> bool
let contains2 person =
let people = set ["Juliet"; "Joe"; "Bob"; "Jack"]
people.Contains(person)
这两个函数产生相同的结果,contains
创建其声明的人员并重新使用它,而contains2
每次调用函数时都会创建其人员集。最终结果:contains
略快一些。因此,了解这里的区别可以帮助您编写更快的代码。
答案 3 :(得分:3)
看起来像功能体的分配机构可能会让一些程序员不知道。通过赋值返回函数,您可以使事情变得更有趣:
let foo =
printfn "This runs at startup"
(fun () -> printfn "This runs every time you call foo ()")
我刚刚在http://blog.wezeku.com/2010/08/23/values-functions-and-a-bit-of-both/写了一篇关于它的博文。