我有compile
函数,该函数采用AST并使用汇编指令生成字符串。在其中创建一个StringBuilder对象。同样在compile
内部,有很多本地函数,例如emitIf
,emitLet
等。
定义局部函数的原因是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
)的函数,而不将其传递给每个函数?
答案 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
函数及其子函数(emitExpr
,emitIf
等内部)中,您可以使用emitn "foo"
,它将添加字符串“ foo \ n ”添加到您在compile
开头创建的StringBuilder实例中。 (当然,每次您调用该函数时,它将是一个不同的实例)。但是您也有可用的emitn
,emitfn
等通用版本,这使得单元测试FAR更容易。