我编写了以下代码来测试F#中的一些MonteCarlo代码。
我的问题是我只在控制台中看到随机数和“oi”一次。我调用oneRun
函数两次,但它看起来只运行一次。
以下是代码:
let genRandomNumbers count =
let rnd = System.Random()
printf "oi "
List.init count (fun _ -> rnd.NextDouble ())
let oneRun =
let numberofClicks = 0
let randomNumber = genRandomNumbers 50
let action numberofClicks random = if random <= 0.10
then numberofClicks+1
else numberofClicks
randomNumber |> Seq.iter (printf "%f ")
randomNumber |> List.fold action numberofClicks
[<EntryPoint>]
let main argv =
let a = oneRun
printf "%d " a
let b = oneRun
printf "%d " b
let key_info = Console.ReadKey()
0 //
任何提示?想法?
答案 0 :(得分:9)
为了扩展Mankarse的正确注释,用于定义值和函数的F#语法看起来非常相似,因此很容易在它们之间混淆。
这是一个值:
let sum = 42
这是一个功能:
let addThree x = x + 3
值和函数都可以跟随块,而不仅仅是单行:
let sumWithSideEffects =
// This will only be evaluated once
printfn "Side effect happens here"
42
let addThree x =
// This will run every time you call the function
let result = x + 3
printfn "Added three to %d and got %d" x result
result
声明名称的let
声明是一个值。值只评估一次,因此值中的任何副作用都只会发生一次。 它们发生的时间并不完全由语言规范定义,所以你不能指望副作用何时发生。另一方面,每次调用函数时都会对函数进行求值。
现在,当你有一个不带参数的函数时,你如何声明它?好吧,你通过给它一个参数声明它,但是无关紧要的参数。具体来说,您声明它采用类型为unit
的参数。 unit
类型是F#中的特殊类型。它基本上对应一个空元组,并写为()
。
考虑一分钟的空元组类型。如果你有两个bool
值的元组,那么这个元组有多少可能的值?四:可以是(false, false)
,(false, true)
,(true, false)
或(true, true)
。如果您的元组只有一个 bool
,则它可能有两个值:(true)
或(false)
。如果你有一个零值的元组(无论什么类型:bool,int,string,无关紧要),那么它只有一个可能的值:()
,空元组。由于这是一种只有一个可能值的类型,因此它被称为unit
类型。
因此,如果您想要一个函数而不是一个值,但该函数不需要采用任何有意义的参数,那么您可以这样定义:
let myFunction () =
printfn "I'm being called purely for the side effects"
请注意我如何在函数名和unit
参数之间放置一个空格。你实际上 没有那个空间 - 编写let myFunction() = ...
是完全合法的 - 但我希望你看到()
不仅仅是函数声明语法,它是实际类型的实际值。当你开始使用函数进行高级操作时,这种区别变得很重要,所以我希望你现在就清楚它。
unit
类型是专门处理的:因为unit
只有一个可能的值,你已经知道了你的函数将被调用什么值,所以你真的不需要将它分配给一个名字。所以F#允许你通过在参数列表中只有一个unit
来声明一个输入类型为()
的函数,而不是让你选择一个你从未在函数体中实际使用的名称。 / p>
我希望这能为你解决问题。