【问题标题】:Forcing let to bind to a function instead of a value强制 let 绑定到函数而不是值
【发布时间】:2016-08-12 08:29:44
【问题描述】:

我有这段代码应该生成随机名称:

let generateName =
    let rnd = System.Random()
    let c1 = rnd.Next(65, 90) |> System.Convert.ToChar |> string
    let c2 = rnd.Next(65, 90) |> System.Convert.ToChar |> string
    let n = rnd.Next(0, 999)  |> string
    c1 + c2 + n

这计算为一个字符串,这不是我想要的。添加单元参数可以解决问题,但现在我必须像 C# 函数一样调用我的函数:

let myFunc() =
    "Hello"

myFunc()

这是我必须这样做的方式,还是有更惯用的方式?

【问题讨论】:

    标签: f#


    【解决方案1】:

    TL;DR: () 在这种情况下的含义与它在 C# 中的含义完全不同,所以不要像在 C# 中那样格式化它——使用 let myFunc () = 和 @987654324 @ 而不是,它可以更好地反映实际语义,并反过来阐明您如何思考和理解代码。


    在 C# 中,() 表示一组空参数(用于函数/构造函数定义)或参数(用于函数/构造函数调用站点);即,它定义或调用 nullary 函数。在 F# 中,()unit 类型的文字,类似于 42int 类型的文字;也就是说,它本身就是一个值,就像[] 是一个空列表的值一样。这种差异有很多小含义。

    在 F# 中,当您定义一个只有 () 参数的 let 函数时,如在 let myFunc() = 中,您实际上是在使用模式匹配语法来定义一个 带有unit 类型参数的一元函数(不是一个空函数!)。这种模式匹配的特殊例子被认为是理所当然的,以至于很多人一开始就没有意识到它是模式匹配。但实际上,将函数定义为 let myFunc () = 而不是 let myFunc (_:unit) = 类似于使用 let myFunc [] = 而不是 let myFunc (x:'a list) =(然后断言 x 为空)。

    在 F# 中,当您调用let 函数和() 时,如在myFunc () 中,您并不是在表示“无参数”;实际上,您提供了一个 unit 类型的参数,它的奇异值经常被使用,以至于它有自己的文字语法:()

    要说服自己unit 与“无参数/参数”不同,实际上只是另一个参数/参数,请考虑以下事实是完全合法的:

    let myFunc() (i:int) (_:unit*unit) = i
    let n = myFunc() 42((),())
    printfn "%d" n
    

    如您所见,给予unit 特殊的空白处理是愚蠢的,因为它不是特殊的。 ;-]

    总之,由于通常(有必要?)用空格分隔任何 命名 参数/参数,因此 惯用 保持一致并与 符号模式/值:

    let myFunc () =
        "Hello"
    
    myFunc ()
    

    【讨论】:

    • “惯用语”可能是一个强词。例如,FSharp.Core 源代码不使用这种样式。 github.com/fsharp/fsharp/tree/master/src/fsharp/FSharp.Core。我个人在风格之间来回跳跃,最终得到了非空格变体。虽然unit 是一个arg,但我发现它有一个特殊的含义——“运行这个函数”。
    • 事实上,我曾经甚至在所有函数中都包含一个额外的(),例如let f()=rand()g x () = rand()+xfg 1 可以被同等对待。但是,与例如使用时效果不佳。 map;额外的参数把它扔掉了 区别?副作用。所以理想情况下,任何有副作用的东西,即使存在其他参数,我也会添加额外的()。遗憾的是,它在 F# 中看起来很傻,所以我搬到了 Haskell,在那里它更有意义,并且根据需要进行区分。
    【解决方案2】:

    不,这就是 F# 的工作原理。 F#中的每个函数都必须有一个参数(具有多个参数的函数被拆分为多个函数,一个参数返回一个中间函数),每个函数都必须返回一些东西,即使它是单位。

    【讨论】:

    • 从来没有这样想过,现在更有意义了!
    【解决方案3】:

    这正是它的工作原理。没有“有用”参数的函数需要有一个unit 参数才能真正使其成为一个函数。

    将函数名和() 用空格隔开的情况并不少见,以使它看起来少了一点方法性和更多的功能性,但这纯粹是装饰性的。

    【讨论】:

      猜你喜欢
      • 2016-08-25
      • 2011-03-20
      • 2015-06-01
      • 2013-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-23
      相关资源
      最近更新 更多