类型推断 F# - 如何生成新变量?

Type inference F# - how to generate fresh variables?

我正在尝试在 f# 中开发用于类型推断的算法 W,但我想了解如何正确编写用于生成新变量的函数。

其实我的功能是

let counter = ref -1

let generate_fresh_variable () : string =
    let list_variables = ['a' .. 'z'] |> List.map string
    counter.Value <- !counter + 1
    list_variables.Item(!counter)

但我对这个解决方案不满意,有人可以给我其他更好的想法吗?

如果你真的想用一个不纯的函数来做这个,我会这样写:

let mutable counter = -1

let generate_fresh_variable () =
    counter <- counter + 1
    counter + int 'a'
        |> char
        |> string

备注:

  • 参考单元格已过时。如果您需要杂质,请改用可变变量。 (或者,如果你真的想坚持使用参考单元格,更新它的规范方法是使用 :=,而不是直接分配给底层 Value。)
  • 无需维护潜在变量名称列表(尤其是无需在每次生成新变量时重建整个列表)。
  • 如果您需要超过 26 个变量会怎样?

如果您想使用一些更复杂的 F# 技巧,您可以使用序列表达式创建无限的名称序列(这使得处理循环和处理 >26 个名称变得非常容易):

let names = seq {
  for i in Seq.initInfinite id do
    for c in 'a' .. 'z' do
      if i = 0 then yield string c
      else yield string c + string i }

获取新名称的函数然后会从序列中选择下一个名称。您需要使用底层枚举器来执行此操作。另一个不错的技巧是将状态隐藏在局部变量和 return 使用 lambda 的函数中:

let freshName = 
  let en = names.GetEnumerator()
  fun () -> 
    ignore(en.MoveNext())
    en.Current

然后根据需要多次调用 freshName()