我在这里编写了一个字符串构建计算表达式 (链接)。
open System.Text
type StringBuilderUnion =
| Builder of StringBuilder
| StringItem of string
let build sb =
sb.ToString()
type StringBuilderCE () =
member __.Yield (txt : string) = StringItem(txt)
member __.Yield (c : char) = StringItem(c.ToString())
member __.Combine(f,g) = Builder(match f,g with
| Builder(F), Builder(G) ->F.Append(G.ToString())
| Builder(F), StringItem(G)->F.Append(G)
| StringItem(F),Builder(G) ->G.Append(F)
| StringItem(F),StringItem(G)->StringBuilder(F).Append(G))
member __.Delay f = f()
member __.Zero () = StringItem("")
member __.For (xs : 'a seq, f : 'a -> StringBuilderUnion) =
let sb = StringBuilder()
for item in xs do
match f item with
| StringItem(s)-> sb.Append(s)|>ignore
| Builder(b)-> sb.Append(b.ToString())|>ignore
Builder(sb)
let builder1 = new StringBuilderCE ()
注意到底层类型是不可变的(包含的
StringBuilder
是可变的,但不必如此)。每个yield不是更新现有数据,而是将当前状态和传入输入组合在一起,得到一个新的
StringBuilderUnion
实例。您可以使用F#列表来完成此操作,因为向列表头添加元素只是构造新值而不是突变现有值。
使用
StringBuilderCE
的方式如下:
//Create a function which builds a string from an list of bytes
let bytes2hex (bytes : byte []) =
string {
for byte in bytes -> sprintf "%02x" byte
} |> build
//builds a string from four strings
string {
yield "one"
yield "two"
yield "three"
yield "four"
} |> build
注意使用yield
而不是let!
因为我实际上不想在计算表达式中使用该值。
Option
的新类型,因为语言中已经存在一个。也许可以使用OptionWithItem
或类似的名称。其次,如果你有答案,应该将它与其他答案一起发布。你仍然可以标记帮助你找到答案的那个答案为“the”答案,但这样可以清楚地区分问题和答案。 - N_A