В вашей ситуации я бы, вероятно, определил группу функций в модуле, которые принимают явный параметр 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 \ nmsgstr "экземпляру StringBuilder, который вы создали в начале compile
.(Конечно, каждый раз, когда вы вызываете функцию, это будет другой экземпляр).Но у вас также есть общедоступные версии emitn
, emitfn
и т. Д., Что облегчает модульное тестирование FAR.