2011-09-04 5 views
15

私は過去にSMLで少し仕事をしましたが、今はもっと興味深い部分に着手し始めています。SML:構造体の実装を隠すためにabstypeを使用し、シグネチャを使用することの違いは何ですか?

abstype...with...endコンストラクタを使用すると、実装の詳細を隠しておくことができます。また、作成したいものの署名を作成し、:>演算子を使用して、そのシグネチャを守って実装の詳細を隠した構造にすることもできます。

署名/構造体は、abstypeのより一般的なバージョンではありませんか?署名/構造ではできない偽造物で私は何ができますか?なぜ私はabstypeを使いたいのですか?

ありがとうございました!一例として、

:私が今までabstypeを使用したいと思うのはなぜ

signature SET = sig 
    type set 
    val empty: set 
    val insert: int * set -> set 
    val member: int * set -> bool 
end 

structure Set :> SET = struct 
    type set = int list 
    val empty = [] 
    fun insert(x, s) = x::s 
    fun member(x, []) = false 
     | member(x, h::t) = (x = h) orelse member(x, t) 
end 

は、少なくともとして強力な

abstype AbsSet = absset of int list with 
    val empty = absset([]) 
    fun insert(x, absset(s)) = absset(x::s) 
    fun member(x, absset([])) = false 
     | member(x, absset(h::t)) = (x = h) orelse member(x, absset(t)) 
end 

として

答えて

8

ですか?

最も簡単に始めると、あなたはしません。ちょっと、私は一つの正当な理由を考え出すことができません。


署名/構造abstypesのちょうどより一般的なバージョンではありませんか?

私はSMLの歴史を見ておかなければなりません。不透明(...:> ...)は、その目的の「抽象的」インスタンスを作成することであったモジュール1.3.9. opaque signature matching :>

約本smlnj文書...に説明したように、署名マッチングはSML '90の一部ではなかったです署名SIG。この機能はSML '90からさまざまな理由で除外されましたが、その必要性は本当にありました。

私はそれを含めていないため推論については考えているが、私の知る限りマックイーンはSML '90の一部であったabstypeの「遠く」だったし、いくつかの理由を知っているとして、SMLに削除されませんでした'97(多分下位互換性ですか?)

しかし、基本的に違いがあります。abstypeは、モジュール/署名/ファンクタがモジュールシステムの一部であるコア言語の一部です。


私は署名/構造で行うことはできませんabstypesで何ができますか?

私は何も思い付きません。しかし、私はあなたが不透明なシグネチャのマッチングを使用することができ、abstypeではできないいくつかの例を構築するのは簡単だろうと確信しています。


UPDATE

後継-mlのウィキからのページDegrade abstype to derived formは実際にabstypeが残っている程度の小さな非公式の記述が含まれています。

他の多くの場合と同様に、Defects in the Revised Definition of Standard ML紙のセクションも参照しています。このページには、abstypeの定義におけるいくつかの「マイナー」エラー/欠陥の詳細が含まれています。 「標準MLの改訂された定義」は、SML'97の定義である。

+0

今すぐリンクが修正されました。 :) –

+1

モジュールでできないabstypeで(少なくとも普通のSML'97で)できる唯一のことは、抽象型を '' let''の中でローカルに定義していることです。しかし、それは誰もが燃え尽きる必要性を感じたことではありません... –

3

abstypeが依然として必要な大きな理由の1つは、現実的なアプリケーションのための最上位のきれいな印刷です。これはSML/NJとPoly/MLの交差点を指しています.Mltonがこの点でどのように機能するかはわかりません(適切なトップレベルを持っていません)。

タスクは単純です:抽象データ型(等価性を漏らさないもの)を定義し、そのために最上位のきれいなプリンタを提供します。 - コンパイラ固有の行が必要

structure A1: 
sig 
    type t val a: t val b: t -> t val print: t -> string 
end = 
struct 

abstype t = A of int 
with 
    val a = A 42 
    fun b (A i) = A (i + 1) 
    fun print (A i) = "{"^Int.toString i^"}[1]" 
end 

end; 

(* works for Poly/ML 5.3, 5.4, 5.5: 
PolyML.addPrettyPrinter (fn depth => fn pretty => fn x => PolyML.PrettyString (A1.print x)); 
*) 

(* works for SML/NJ 110.xx: 
CompilerPPTable.install_pp ["A1", "t"] (fn pps => fn x => PrettyPrint.string pps (A1.print x)); 
*) 

A1.aは、この変な例では{42}[1]を印刷する必要があります:私は知っている唯一の(準ポータブル)答えはSML'90スタイルの非不透明シグネチャマッチングと平野古いabstypeを使用していますコメントされていないこれは間違いなくSML'97標準の外にあるか、それ以降のML'2000以降の試みですが、SML/NJとPoly/MLの両方で動作します。ある意味では、古いSML'90とpre-SMLの文化が光っているのを見ています.LISPのトップレベルのハッキングもあります。 (上記の構造定義へのludesは、コンパイル時にSML toplevelを呼び出して、両方で動作するようにして、ソースを移植可能にする面白いラッパーに変えることができます)。

Isabelle 、HOL4、ProofPower、toplevel MLかなりの印刷は、SMLの標準作家が言うかもしれないものであれ、不可欠です。私は右のすべての奇数のケースを持っていることを願ってい

structure A2 :> 
sig 
    type t val a: t val b: t -> t val print: t -> string 
end = 
struct 

datatype t = A of int 

val a = A 42 
fun b (A i) = A (i + 1) 
fun print (A i) = "{"^Int.toString i^"}[2]" 

(* works, but non-portable: 
val _ = 
    PolyML.addPrettyPrinter (fn depth => fn pretty => fn x => PolyML.PrettyString (print x)) 
*) 

(* does not work (scope problem -- no pp): 
val _ = 
    CompilerPPTable.install_pp ["A2", "t"] (fn pps => fn x => PrettyPrint.string pps (A2.print x)); 
*) 

end; 

(* does not work (no pp): 
    PolyML.addPrettyPrinter (fn depth => fn pretty => fn x => PolyML.PrettyString (A2.print x)); 
*) 

(* does not work (no pp): 
CompilerPPTable.install_pp ["A2", "t"] (fn pps => fn x => PrettyPrint.string pps (A2.print x)); 
*) 


structure A3 :> 
sig 
    type t val a: t val b: t -> t val print: t -> string 
end = 
struct 

type t = int 

val a = 42 
fun b i = i + 1 
fun print i = "{"^Int.toString i^"}[3]" 

(* does not work (overrides pp for int): 
val _ = 
    PolyML.addPrettyPrinter (fn depth => fn pretty => fn x => PolyML.PrettyString (print x)) 
*) 

(* does not work (scope problem -- no pp) 
val _ = CompilerPPTable.install_pp ["A2", "t"] (fn pps => fn x => PrettyPrint.string pps (A2.print x)); 
*) 

end; 

(* works: 
    PolyML.addPrettyPrinter (fn depth => fn pretty => fn x => PolyML.PrettyString (A3.print x)); 
*) 

(* does not work (no pp): 
CompilerPPTable.install_pp ["A3", "t"] (fn pps => fn x => PrettyPrint.string pps (A3.print x)); 
*) 

はここ:>に一致SML'97不透明な署名に沿ったよりますが、一様に動作しない2つのバージョンがあります。 Poly/MLでは元の表現が印刷されますが、SML/NJでは何も印刷されません(プレースホルダとしてダッシュだけが印刷されます)。 「タグなし」の不透明なタイプは特に厄介です.Poly/MLではintのためにかなりのプリンタをオーバーライドしますが、SML/NJでは何もしません。これも悪いことです。

+0

うわー、それは私がこれまで聞いたことは初めてです。特定の実装の非移植的なハックフィーチャとの間違った相互作用によって、古い古い構造を動機づけする気持ちはどういうものか分かりません。 :) –

関連する問題