7

在 OCaml 或 F# 中,具有以下形式的连续 let 绑定是典型的:

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

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

4

2 回答 2

11

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

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

当然,总是有注释和空行:

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
于 2012-08-08T21:15:34.557 回答
7

除了 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>

一个使用的小例子|>

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

You'll end up needing |- and flip in more realistic examples. This is known as point-free or tacit programming.

于 2012-08-09T13:42:47.337 回答