繁体   English   中英

F#代码执行顺序

[英]F# Code Execution Order

关于F#的另一个noob问题。

如果我有以下代码......

let ExeC =
    printfn "c"
    3

let ExeB b = 
    printfn "b"
    2

let ExeA = 
    printfn "a"
    1

printfn "Example %d " ExeA
printfn "Example %d " (ExeB 1)
printfn "Example %d " ExeC

输出如下......

c
a
Example 1
b
Example 2
Example 3

这里看起来很不寻常的是代码执行的顺序。在上一个问题中,Brian提到了一些关于表达式的问题,我希望有人可以解释一下这个问题。 几乎看起来编译器是智能地预先执行事物来计算值...但我不知道?

ExeAExeC不是函数,而是单个值。 编译器确保值按照在源文件中声明的顺序初始化,因此这里发生的是:

  1. ExeC初始化
  2. ExeA初始化
  3. 使用ExeA的初始值打印Example 1
  4. ExeB函数被正常调用
  5. 使用ExeC的初始值打印Example 3

如果你想让ExeAExeC真正变得懒惰 - 也就是说,控制它们的副作用何时运行 - 你可以把它们变成接受unit函数:

let ExeC () =
    printfn "c"
    3

let ExeB b = 
    printfn "b"
    2

let ExeA () = 
    printfn "a"
    1

printfn "Example %d " (ExeA ())
printfn "Example %d " (ExeB 1)
printfn "Example %d " (ExeC ())

作为Tim回答的后续内容,我想你可能会对你偶然发现的事情有所了解。 在您的示例中,ExeC和ExeA利用通过词法作用域和闭包来组织代码的功能样式。 让我展示一个更有力的例子。

let calc n =
    //...
    let timesPieDiv4 = 
        let pie = 3.14
        let pieDiv4 = pie/4.
        n * pieDiv4

    //...

在这里, timesPieDiv4不是一个函数,但它的主体包含一系列子计算,这些子计算不会暴露给其余的calc函数。 在像C#这样的语言中,你有两种选择,它们都不吸引我。 第一个选项是简单地在calc主体中声明piepieDiv4 ,但是它们不太清楚它们是如何被使用的并且你弄脏你的变量空间。 另一种选择是将这些子计算分解为一个单独的私有辅助函数。 但是我不喜欢这样的功能,因为很多人很难分析你的复杂算法,因为你总是在寻找各种实现部分。 此外,它还有很多锅炉板代码和价值传递。 这就是为什么F#函数默认是“公共”的,词法作用域和闭包允许您在面向公众的函数中分层组织“私有”函数和值。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM