2017-07-04 16 views
1

右、私はラスカルにこのデータ型を持っている:ラスカルの代数データ型の継承?

data Primitive = Any() | Void() | Int(); 

そして、このようなことを行うことができる::私は何をしたいか

data Type = Any() | Void() | Int() | Not(Type l) | And(set[Type] es) | Or(set[Type] es); 

は、このような別のタイプを定義している

Primitive p = Any(); 
Type d = p; 

たとえば、簡略化するとPrimitiveと一致するのはTypeです。このような何かを:

public Type reduce(Not(Primitive p)) = p; 

現在、私が見ることができる唯一のソリューションはそうのように、それぞれの場合については、上記のルールを拡大することです:私はこれを行う方法があります推測している

public Type reduce(Not(Any)) = Any(); 
public Type reduce(Not(Void)) = Void(); 
public Type reduce(Not(Int)) = Int(); 

、しかし、私はまだそれを理解していない...考え?

答えて

1

短い答え:ものの抽象データ型は、には直接継承が存在しない(すなわち、それらの定義はモジュール間で拡張することができる)を拡張することができます。

回避策

ソリューションここ

data Type = Any() | Void() | Int() | Not(Type l) | And(set[Type] es) | Or(set[Type] es); 

bool isPrim(Any()) = true; 
bool isPrim(Void()) = true; 
bool isPrim(Int()) = true; 
default bool isPrim(Type t) = false; 

Type reduce(Not(Type t)) = t when isPrim(t); 
default Type reduce(Type t) = t; 

Typeためのすべてのコンストラクタは、単一のADTであり、述語isPrimは、プリミティブを選択します。たとえば、reduce(Not(Void()))Void()に縮小されます。

溶液Bここ

data Primitive = Any() | Void() | Int(); 

data Type = prim(Primitive p) | Not(Type l) | And(set[Type] es) | Or(set[Type] es); 

Type reduce(Not(prim(Primitive p))) = prim(p); 
default Type reduce(Type t) = t; 

プリミティブは別ADT Primitiveに収集され、それらは、コンストラクタprim介しTypeに含まれています。今すぐreduce(Not(prim(Void())))prim(Void())に縮小されます。

決勝ノート

  • 我々はまた、(溶液Bのように余分なコンストラクタprimなし)の継承を持つことを好むが、我々はそれが含まれていなかった様々な技術的な理由からでしょう。望ましいとはいえ、私たちがこれまでに行うことは確実ではありません。
  • ファンクションの他の宣言が一致しない場合は、defaultが前に付いているファンクションには、キャッチオールがあります。
  • すべての機能は、privateで始まる場合を除き、publicです。
+0

Thanks Paul。実際、 'isPrim'マッチャーは、別の' prim'コンストラクターを使っているよりも優れています。私はそれに渦を立てます。 – redjamjar

1

良い質問。 Rascalにはユーザー定義のサブタイプがありません。データ型の型は公称です。それは理論上あなたの質問に答えるので、それはどのように実際に働くのですか?

  • データ型の答えは、構文の種類によって若干異なります。
  • データ構造の階層をモデル化するために、さまざまなイディオムがありますが、簡単にするためにここでは3つしか示しません。

がここに新しいタイプを追加する必要としない新しい機能とデータ型を拡張する方法ですが、これがあなたの意図したものの過近似モデル生成:

// first the primitive types are defined (I've added Not here to make a point later): 
data Type = Any() | Void() | Int() | Not(Type l); 

// then the extension is added (perhaps in a different module) 
data Type = And(set[Type] es) | Or(set[Type] es); 

// the second definition adds its alternatives also to the child of `Not`. 

を第二の方法は、より多くのですもちろん

// we give the original type a unique name: 
data Primitive = Any() | Void() | Int(); 

// For the extension the Primitive type is not polluted with the new constructors, but 
// it was wrapped inside a singleton constructor `prim` 
data Type = prim(Primitive super) | And(set[Type] es) | Or(set[Type] es); 

は、この第二の解決策は、あなたがを追加するようになります:元Typeが延長されず、「ジャンク」は誤って追加されていないので、実際の拡張子に近いです0のコンストラクタが可能なパターンマッチで一致しますが、/ディープマッチ演算子では可能な限り無視します。たとえば:

bool evalt(prim(p)) = evalp(p); 
bool evalp(Any()) = true; 
bool evalp(Not(p)) = !evalp(p); 

bool containsVoid(Type t) = /Void() := t; 

は今のシンタックスタイプについての話は似ていますが、構文タイプでチェーンルールが見えないので、いくつかの追加の風味を与える:

syntax Primitive = "any" | "void" | "int"; 

// notice the first chain rule or "injection" of Primitive into Type: 
syntax Type = Primitive | left Type "∧" Type > left Type "∨" Type; 

bool evalt((Type) `any`) = true; // the chain rule is parsed but invisible 

人々がに暗黙の連鎖を追加するために議論されています抽象的なデータ型も同様に、そのようなサブタイプをシミュレートすることが魅力的です。スカラの暗黙のようなものになると思う。陪審員はまだそれに出ていません。

+0

ありがとうございました。私は、 'prim'コンストラクタがそのトリックを行うかもしれないと思います。あなたが言うように少し醜いですが、それを働かせていることは私の今の主な関心事です:) – redjamjar