F#功能和。值

时间:2010-08-24 08:37:45

标签: f#

这是一个非常简单的问题,我只是想检查一下我正在做什么,以及我如何解释F#是有道理的。如果我有陈述

let printRandom = 
  x = MyApplication.getRandom()
  printfn "%d" x
  x

而不是将printRandom作为函数创建,F#运行一次,然后为其赋值。所以,现在,当我调用printRandom时,不是获取新的随机值并打印它,我只是得到第一次返回的内容。我可以解决这个问题:

let printRandom() = 
  x = MyApplication.getRandom()
  printfn "%d" x
  x

这是在无参数函数和值之间进行区分的正确方法吗?这对我来说似乎不太理想。是否会对咖喱,成分等产生影响?

4 个答案:

答案 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/写了一篇关于它的博文。