F# 中的阴影
Shadowing in F#
我想知道为什么 F# 允许阴影,尤其是在同一范围内。
我一直认为纯函数式编程构造中的值绑定类似于 algebra/mathematics 中的赋值。
例如,
y = x + 1
将是一个有效的数学表达式,但是
y = y + 1
不会。
但是,由于阴影,
let y = y + 1
是 F# 中完全有效的表达式。
为什么语言允许这样做?
对此最正确的答案是因为创建者 Don Syme 认为添加到该语言中是一项有用的功能。
不过,它有一些很好的用途。一种是使用 F# 样式的可选参数时:
type C() =
member _.M(?x) =
let x = Option.defaultValue 0 x
printfn "%d" x
F#可选参数是options,带来了高度的正确性和一致性。但是想象一下,一个方法有 3 个或更多可选参数。必须重新绑定每个值并为它们使用不同的名称会很烦人!这是阴影派上用场的一个领域。
编写递归子程序时也很方便。考虑以下 sum
列表的天真实现:
let mySum xs =
let rec loop xs acc =
match xs with
| [] -> acc
| h :: t -> loop t (h + acc)
loop xs 0
我不需要为内循环重新绑定 xs
因为有阴影。因为它是通用的,所以 xs
是我能想到的最好的名字,所以必须为内部循环使用不同的名称会很烦人。
不过,遮蔽也不全是好消息。如果您不小心,一个 open
声明中的类型可能会遮盖先前声明的类型。这可能令人困惑。 F# 编辑器工具可以将绑定与隐藏它们的绑定区分开来,但您无法通过纯文本获得这一点。所以底线是:在 F# 中应用阴影时请仔细考虑。
我想知道为什么 F# 允许阴影,尤其是在同一范围内。
我一直认为纯函数式编程构造中的值绑定类似于 algebra/mathematics 中的赋值。
例如,
y = x + 1
将是一个有效的数学表达式,但是
y = y + 1
不会。
但是,由于阴影,
let y = y + 1
是 F# 中完全有效的表达式。
为什么语言允许这样做?
对此最正确的答案是因为创建者 Don Syme 认为添加到该语言中是一项有用的功能。
不过,它有一些很好的用途。一种是使用 F# 样式的可选参数时:
type C() =
member _.M(?x) =
let x = Option.defaultValue 0 x
printfn "%d" x
F#可选参数是options,带来了高度的正确性和一致性。但是想象一下,一个方法有 3 个或更多可选参数。必须重新绑定每个值并为它们使用不同的名称会很烦人!这是阴影派上用场的一个领域。
编写递归子程序时也很方便。考虑以下 sum
列表的天真实现:
let mySum xs =
let rec loop xs acc =
match xs with
| [] -> acc
| h :: t -> loop t (h + acc)
loop xs 0
我不需要为内循环重新绑定 xs
因为有阴影。因为它是通用的,所以 xs
是我能想到的最好的名字,所以必须为内部循环使用不同的名称会很烦人。
不过,遮蔽也不全是好消息。如果您不小心,一个 open
声明中的类型可能会遮盖先前声明的类型。这可能令人困惑。 F# 编辑器工具可以将绑定与隐藏它们的绑定区分开来,但您无法通过纯文本获得这一点。所以底线是:在 F# 中应用阴影时请仔细考虑。