我已经定义了以下歧视工会的歧视工会:类型的扩展名
type Expr =
| Con of Num
| Var of Name
| Add of Expr * Expr
| Sub of Expr * Expr
| Mult of Expr * Expr
| Div of Expr * Expr
| Pow of Expr * Expr
然后,我创建了一个漂亮的打印功能如下:
let rec stringify expr =
match expr with
| Con(x) -> string x
| Var(x) -> string x
| Add(x, y) -> sprintf "(%s + %s)" (stringify x) (stringify y)
| Sub(x, y) -> sprintf "(%s - %s)" (stringify x) (stringify y)
| Mult(x, y) -> sprintf "(%s * %s)" (stringify x) (stringify y)
| Div(x, y) -> sprintf "(%s/%s)" (stringify x) (stringify y)
| Pow(x, y) -> sprintf "(%s ** %s)" (stringify x) (stringify y)
现在,我想让我的Expr
键入ToString()
方法使用此功能。例如:
type Expr =
| Con of Num
| Var of Name
| Add of Expr * Expr
| Sub of Expr * Expr
| Mult of Expr * Expr
| Div of Expr * Expr
| Pow of Expr * Expr
override this.ToString() = stringify this
但我不能这样做,因为stringify
尚未定义。答案是将Stringify
定义为Expr
的成员,但我不想用这种随时间不断增长的专用方法污染我的初始类型声明。因此,我决定使用一个抽象的方法,我可以在文件的后面执行intrinsic type extension。下面是我所做的:
type Expr =
| Con of Num
| Var of Name
| Add of Expr * Expr
| Sub of Expr * Expr
| Mult of Expr * Expr
| Div of Expr * Expr
| Pow of Expr * Expr
override this.ToString() = this.Stringify()
abstract member Stringify : unit -> string
,但我得到以下编译器错误:
error FS0912: This declaration element is not permitted in an augmentation
的消息并不甚至似乎正确的(我不是创造一个增强型还),但我明白为什么它在抱怨。它不希望我在受歧视的联合类型上创建抽象成员,因为它不能被继承。尽管我不想继承,但我希望它在C#中的行为类似于部分类,我可以在其他地方完成定义(在本例中是同一个文件)。
我结束了“作弊”使用StructuredFormatDisplay
属性的后期绑定功率sprintf
一起:
[<StructuredFormatDisplay("{DisplayValue}")>]
type Expr =
| Con of Num
| Var of Name
| Add of Expr * Expr
| Sub of Expr * Expr
| Mult of Expr * Expr
| Div of Expr * Expr
| Pow of Expr * Expr
override this.ToString() = sprintf "%A" this
/* stringify function goes here */
type Expr with
member public this.DisplayValue = stringify this
虽然现在sprintf
和ToString
两个输出相同的字符串,有没有办法让如果我需要,则输出Add (Con 2,Con 3)
而不是(2 + 3)
。
那么有没有其他方法可以做我想做的事情?
P.S.我还注意到,如果我将StructuredFormatDisplay
属性放在扩充上而不是原始类型上,它不起作用。这种行为对我来说似乎不正确。似乎F#编译器应该将该属性添加到类型定义中或禁用类型增量上的属性。
我想我会接受这个,尽管我可能不会使用它,因为它至少是我没有考虑过的技术。 – luksan