我有这个方法,它接受一个列表并将其转换为字节码字符串。它的工作方式与我期望的一样;但是,我得到一个我不想要的尾随空间。 问题:如何摆脱最后一次追踪0?
Input: byteCode [SC 10; SC 2; SAdd; SC 32; SC 4; SC 5; SAdd; SMul; SAdd]
let rec byteCode (l : sInstr list) : string =
match l with
| [] -> ""
| (SC n :: l) -> "0 " + string n + " " + byteCode l
| (SAdd :: l) -> "1 " + byteCode l
| (SSub :: l) -> "2 " + byteCode l
| (SMul :: l) -> "3 " + byteCode l
| (SNeg :: l) -> "4 " + byteCode l
| (SLess :: l) -> "5 " + byteCode l
| (SIfze n :: l) -> "6 " + string n + " " + byteCode l
| (SJump n :: l) -> "7 " + string n + " " + byteCode l
这可能不会编译,因为我没有给出我的整个程序。
This returns: "0 10 0 2 1 0 32 0 4 0 5 1 3 1 "
I expect: "0 10 0 2 1 0 32 0 4 0 5 1 3 1"
答案 0 :(得分:7)
这样的案例通常表明字符串以过于幼稚的方式连接起来。首先考虑收集结果的所有单个组件,然后调用预定义的String.concat
函数:
let byteCode (l : sInstr list) : string =
let rec byteCode' l =
match l with
| [] -> []
| (SC n :: l) -> "0" :: string n :: byteCode' l
| (SAdd :: l) -> "1" :: byteCode' l
| (SSub :: l) -> "2" :: byteCode' l
| (SMul :: l) -> "3" :: byteCode' l
| (SNeg :: l) -> "4" :: byteCode' l
| (SLess :: l) -> "5" :: byteCode' l
| (SIfze n :: l) -> "6" :: string n :: byteCode' l
| (SJump n :: l) -> "7" :: string n :: byteCode' l
l |> byteCode' |> String.concat " "
String.concat
已经只在各个部分之间添加了分隔符字符串。
这也更清晰,因为它将特定分隔符字符串的实现细节保留在核心逻辑之外,并使其更容易替换 - 想象一下将函数简单地更改为函数中的两个空格的努力。
或者,您可以只使用现有函数,并在最终生成的字符串上调用.Trim()
(或.TrimEnd()
)方法来删除(尾随)空格。
答案 1 :(得分:2)
你可以用这种方式避免递归:
let byteCode (l : sInstr list) : string =
let instrToString (bc : sInstr) : string =
match bc with
| (SC n) -> sprintf "0 %d" n
| (SAdd ) -> "1"
| (SSub ) -> "2"
| (SMul ) -> "3"
| (SNeg ) -> "4"
| (SLess ) -> "5"
| (SIfze n) -> sprintf "6 %d" n
| (SJump n) -> sprintf "7 %d" n
l |> List.map instrToString |> String.concat " "
假设sInstr定义为:
type sInstr =
| SC of int
| SAdd
| SSub
| SMul
| SNeg
| SLess
| SIfze of int
| SJump of int
byteCodes和revserse的函数可能如下所示:
let byteCode (l : sInstr list) : string =
let instrToString (bc : sInstr) =
(match bc with
| SC n -> [0; n]
| SAdd -> [1]
| SSub -> [2]
| SMul -> [3]
| SNeg -> [4]
| SLess -> [5]
| SIfze n -> [6; n]
| SJump n -> [7; n])
String.Join(" ", (l |> List.map instrToString |> List.fold (fun acc lst -> acc @ lst) []))
let toInstr (bcString : string) : sInstr list =
let rec recToInstr bcList =
match bcList with
| [] -> []
| head :: tail ->
match head with
| "0" -> SC(Int32.Parse(tail.[0])) :: recToInstr (tail |> List.skip 1)
| "1" -> SAdd :: recToInstr tail
| "2" -> SSub :: recToInstr tail
| "3" -> SMul :: recToInstr tail
| "4" -> SNeg :: recToInstr tail
| "5" -> SLess :: recToInstr tail
| "6" -> SIfze(Int32.Parse(tail.[0])) :: recToInstr (tail |> List.skip 1)
| "7" -> SJump(Int32.Parse(tail.[0])) :: recToInstr (tail |> List.skip 1)
| _ -> []
recToInstr (bcString.Split(' ') |> Array.toList)