8

私は次の差別的共用体を定義しました。

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ことですが、時間の経過とともに成長し続けるこの特殊なメソッドで、最初の型宣言を汚染したくありません。したがって、ファイルのさらに下にある組み込み型拡張機能を使用して実装できる抽象メソッドを使用することにしました。これが私がしたことです:

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

しかし、次のコンパイラ エラーが発生します。

エラー FS0912: この宣言要素は拡張では許可されていません

メッセージは正しくないように見えますが (型拡張はまだ作成していません)、不平を言っている理由は理解できます。継承できないため、識別された共用体型で抽象メンバーを作成したくありません。継承は本当にしたくありませんが、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

現在sprintfToString両方が同じ文字列を出力しますが、出力が必要な場合とAdd (Con 2,Con 3)は対照的に、出力を取得する方法はありません(2 + 3)

それで、私がやろうとしていることを行う他の方法はありますか?

StructuredFormatDisplayPS また、元のタイプではなくオーグメンテーションに属性を配置すると、機能しないことにも気付きました。この振る舞いは私には正しくないようです。F# コンパイラは、属性を型定義に追加するか、型拡張の属性を許可しないようにする必要があるようです。

4

3 に答える 3

8

ToStringオーグメンテーションで自分を定義することを検討しましたか?

type Num = int
type Name = string

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)

type Expr with
    override this.ToString() = stringify this

ただし、それに醜い副作用があります

warning FS0060: Override implementations in augmentations are now deprecated. Override implementations should be given as part of the initial declaration of a type.
于 2013-08-03T22:28:45.857 に答える