f#-使用公共​​对象而不将其传递到任何地方

时间:2018-09-22 19:25:36

标签: compilation f#

我有compile函数,该函数采用AST并使用汇编指令生成字符串。在其中创建一个StringBuilder对象。同样在compile内部,有很多本地函数,例如emitIfemitLet等。 定义局部函数的原因是StringBuilder对象不必作为附加参数传递给emit函数。但是我觉得这个解决方案有点尴尬。

module Compile
let compile ast =
    let sb = new StringBuilder()
    let emitn s = sb.AppendLine s |> ignore
    let emitfn f = Printf.kprintf emitn f
    let emitLoadNumber (n:int) = 
        emitfn "  mov $%d, %%rax" n

    let rec emitExpr env si =
    //...
    and emitIf isTail env si cond th el =
    //...

作为另一个解决方案,我可以在模块作用域中创建StringBuilder并将本地函数移入模块作用域。
我的问题是:有没有更好的方法来定义一堆使用通用对象(例如流或StringBuilder)的函数,而不将其传递给每个函数?

1 个答案:

答案 0 :(得分:2)

在您的情况下,我可能会在模块中定义一堆带有显式StringBuilder参数的函数,然后使用部分应用程序定义一堆关闭一个特定StringBuilder实例的局部函数。例如,

module Compile

let emitn sb s = sb.AppendLine s |> ignore
let emitfn sb f = Printf.kprintf (emitn sb) f
let emitLoadNumber sb (n:int) =
    emitfn sb "  mov $%d, %%rax" n

let compile ast =
    let sb = new StringBuilder()
    let emitn = emitn sb
    let emitfn = emitfn sb
    let emitLoadNumber = emitLoadNumber sb

    let rec emitExpr env si =
    //...
    and emitIf isTail env si cond th el =
    //...

现在在compile函数及其子函数(emitExpremitIf等内部)中,您可以使用emitn "foo",它将添加字符串“ foo \ n ”添加到您在compile开头创建的StringBuilder实例中。 (当然,每次您调用该函数时,它将是一个不同的实例)。但是您有可用的emitnemitfn等通用版本,这使得单元测试FAR更容易。