【问题标题】:OCaml, F# successive, cascading let bindingsOCaml、F# 连续、级联 let 绑定
【发布时间】:2012-08-06 01:41:39
【问题描述】:

在 OCaml 或 F# 中,典型的 let 绑定形式为:

let a1 = ...
let a2 = ...
let a3 = ...
let f1 = ...
let f2 = ...
let f3 = ... 
f3 a1 a2 a3

在许多情况下,其中一些 let 绑定(例如上面示例中的 f1f2)仅用作紧随其后的表达式或函数的构建块,并且之后不再引用。在其他情况下,确实在“链”的末端使用了一些值(例如上面示例中的 a1a2a3)。是否有任何语法习惯可以使这些范围上的差异明确?

【问题讨论】:

    标签: f# ocaml


    【解决方案1】:

    On可以用这个来明确temp只用在a1的定义中:

    let a1 =
      let temp = 42 in
      temp + 2 in
    let a2 = ...
    

    temp的范围确实仅限于a1的定义。

    另一个模板正在重用相同的名称以隐藏其以前的使用,因此也明确了以前的使用是临时的:

    let result = input_string inchan in
    let result = parse result in
    let result = eval result in
    result
    

    不过,重用同名是有争议的。

    当然总是有 cmets 和空行:

    let a1 = ...
    let a2 = ...
    let a3 = ...
    
    (*We now define f3:*)
    let f1 = ...
    let f2 = ...
    let f3 = ...
    
    f3 a1 a2 a3
    

    编辑:正如 fmr 所指出的,我也喜欢管道运算符。 OCaml中默认没有定义,使用

    let (|>) x f = f x;;
    

    然后你可以写类似的东西

    input_string inchan |> parse |> eval |> print
    

    【讨论】:

    • 并且,稍微扩展一下,如果temp 用于计算多个值,您可以将这些值同时绑定为一个元组:let a1, a2, a3 = let temp = ... in temp + 2, temp - 2, temp * 2
    • 另外,根据 RHS 上表达式的复杂性,您可以考虑“管道”成语 (e |> e |> e |> e)
    【解决方案2】:

    除了 jrouquie 的回答之外,您还可以通过明智地使用函数组合和其他组合器来避免为中间值命名。我特别喜欢Batteries提供的以下三个:

    # let ( |> ) x f = f x;;
    val ( |> ) : 'a -> ('a -> 'b) -> 'b = <fun>
    # let ( |- ) f g x = g (f x);;
    val ( |- ) : ('a -> 'b) -> ('b -> 'c) -> 'a -> 'c = <fun>
    # let flip f x y = f y x;;
    val flip : ('a -> 'b -> 'c) -> 'b -> 'a -> 'c = <fun>
    

    一个使用|&gt;的小例子是

    # [1;2;3]
      |> List.map string_of_int
      |> String.concat "; "
      |> Printf.sprintf "[%s]";;
    - : string = "[1; 2; 3]"
    

    在更实际的示例中,您最终将需要 |-flip。这称为point-freetacit 编程。

    【讨论】:

    • FWIW,|&gt; 是 F# 的反向移植,我相信 flip 来自 Haskell。
    猜你喜欢
    • 1970-01-01
    • 2014-08-13
    • 2014-04-20
    • 2020-02-16
    • 2014-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多