OCaml, F#连续、级联let绑定

7

在OCaml或F#中,典型的做法是使用连续的let绑定来定义变量:

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

在许多情况下,一些let绑定(例如上面示例中的f1和f2)仅用作其后立即跟随的表达式或函数的构建模块,并且之后不再引用。在其他情况下,某些值确实在“链”的末尾使用(例如上面示例中的a1、a2和a3)。是否有一种语法习惯可以明确这些作用域的差异呢?
2个回答

11

可以使用这个方法来明确表示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

重复使用同一个名称是有争议的。

当然,你总是可以使用注释和空行:

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

2
并且,稍微扩展一下,如果temp用于计算多个值,你可以将这些值同时绑定为一个元组:let a1, a2, a3 = let temp = ... in temp + 2, temp - 2, temp * 2 - Daniel
2
此外,根据 RHS 表达式的复杂程度,您可能会考虑使用“管道”习语(e |> e |> e |> e)。 - fmr

7
除了jrouquie的回答之外,您还可以通过巧妙地使用函数组合和其他组合器来避免为中间值命名。我特别喜欢以下三个组合器,它们由Batteries提供: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>

一个使用 |> 的小例子是:
# [1;2;3]
  |> List.map string_of_int
  |> String.concat "; "
  |> Printf.sprintf "[%s]";;
- : string = "[1; 2; 3]"

在更为实际的例子中,你会发现需要使用 |-flip。这被称为无点风格暗示编程


顺便提一下,|> 是从 F# 中借鉴过来的,而 flip 则是来自 Haskell。 - J D

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接