メモ
概要
Moduleを値として扱えるように。この手の論文は多い。
型づけは決定可能。
肝
pack s as S
open e as X
とsignatureのマッチング
Type Syntax
Core types (u)
u ::= t
| u -> u'
| int
| sp.tSignature Bodies (B)
B ::= type t = u; B //transparent (manifest)Signature Expressions (S)
| type t; B //abstract (opaque)
| val x : u; B
| structure X : S; B //Nest
| εBS ::= sig B end
| T // signature identifiersignatureに名前を付けられる (module type S = sig .. end)
Term (structure)
Structure Bodiesb ::= type t = u; b //transparent (manifest only)
| val x : u; b
| structure X = s; b //Nest
| functor F (X:S) = s; b
| signature T = S; b
| εbStructure Expression
s ::= sp
| struct b end
| F(s)
| s :> S // opaque constraint (s : S)
Semantic Objects
α ∈ Var
M, N, P, Q ∈ VarSet
u ∈ Type (::= α | u -> u' | int)
φ ∈ Real (= Var -> Type) // 型変数への代入
S ∈ Str (= TypeId -> Type, ValId -> Type, StrId -> Str)
L ∈ Sig (::= ΛP.S) // semantic signatures ※
X ∈ ExStr (::= ∃P.S) // existential structures
F ∈ Fun (::= ∀P.S -> X) // semantic functors
C ∈ Context (型, signature, 変数, structure, functorの名前をlookup)
ΛP.S
Pは抽象型の集合
Sはstructure
型は type t |> α や type t |> int のように書く。
S enriches S' (Sの方がS'より豊か 高い機能(?) 多くのフィールド!)
1. D(S) ⊇ D(S')
2. S'に含まれるt,xはS, S'で等しい
3. S'内のstructureについても再帰的にenrichであるsubtypingは?? α ≧ int (型、変数に対して)
∀P.S -> X instantiates to a functor instance S' -> X' (∀P.S -> X > S' -> X')
代入(Realization) D(φ) = P なるφがあってφ(S) = S' かつ φ(X) = X'φ(∀P.S -> X) = φ(S) -> φ(X) ... S' -> X'
代入は全ての変数に。イメージ↓
(struct type 'a t type b' t end)[int/'a]
... (struct type 'a t type b' t end)[int/'a, b''/b']
(struct type int t type b'' t end)
代入[int/'a]は'b,'c (!≡ 'a) については適当な名前の付け替えでよい
semantic structure S matches a signature ΛP.S'
D(φ) = P, S ≧ φ(S') (enriches)
プログラムテキストからSemantic Signaturesへの変換。 e.g.) structure X : S; B |> ΛP∪Q.X : S,S' structure ...
性質
structureの同じレベル内で名前の重複がない。
abstractな型に型変数が対応づけられている。この型変数は新たに導入し、ΛP.Sの Pの部分にその型変数が入る。type t = u の所の u の評価をいつ行うか?
Classification Judgements (Typing Judgements)
Package Types
差分Core types
+ <S>Core Expressions
+ pack s as S
| open e as X : S in e' pack s as S : <X>packするときにsignatureをつけておく。
何を提供するか?
openするときにas Xという名前をつけて使う。signatureもつける。
何を使用するか?例)
Fig 8structure Sieve struct type state = <Stream>; //package type val start = pack TwoOnwards as Stream; // TwoOnwards :> Stream val next = λs:state.open s as S:Stream in pack Next(S) as Stream; val value = λs:state.open s as S:Stream in S.value S.start end;next, value は Sieve.state -> Sieve.state !?
Core内でfunctor適用を書ける。 (nextのbody)
package typeがCoreとModuleをつなぐちょっと考えてみる
Core -> Module へのアクセス
package typeをCore typeとして扱える
package typeのついたものを関数の引数としてとることができる。
Module -> Core
functor適用 -> 関数適用に持っていく (nthstateはpackage typeの値を返す)
再帰が書ける!!val nthstate = fix λnthstate:int->Sieve.state. λn:int. ifzero n then Sieve.start else Sieve.next (nthstate (pred n)) val nthprime = λn:int.Sieve.value (nthstate n)
推論規則
Signature Expressions (S)
Denotation Semantics
sp : path (::= X | sp.X)素材
first_module_rule.tex
推論規則の検索といきたかったところだが。
typing.tex
OnTwowardsの右辺の型付けの木
Stream はsignature STREAMとでも書こうかmodule type STREAM = sig type : state; //なにか状態をもつ val start: state; val value: state -> int //とりだし end2以上の整数のSTREAMを定義 TwoOnwards
TwoOnwards に Streamのtailを返すfunctor Next を適用する。
Nextを再帰的に適用して素数表を生成。N番以降の素数をもつSTREAMを作る。登場人物整理
STREAM, STATE .. signature
TwoOnwards .. structure 2以上の整数列を実装したもの
Next, Value .. STATEを引数にとるfunctor
STREAM -> STREAM
relation.vcg
stream.vcgStreamをsemantic signatureにもっていったあとのイメージ(Not / OK)
opaque.vcg
structure NAME = struct ... end
structure NAME = PATH etc..
structureで名前付けV(O) ... O中の自由変数
functorのsignatureがない。functorは適用されてナンボらしい。
内部のfunctorにしかアクセスできない?? 外部モジュールのfunctorを使用するのは無理????
# module type A = sig module A : functor (Arg : sig type t end) -> sig type t = Arg.t end end;;
module type A =
sig module A : functor (Arg : sig type t end) -> sig type t = Arg.t end end
一意に決まる??
type?
semantic objects?
Xはstructureの名前を表すメタ変数
existential structure の束縛変数はfunctorに絡む。内部で発生した型変数 を外は受け継ぐ。
functor instantiationに絡む。
opaque constraintに絡む。( OnTwowards :> Stream )
Fig4の言わんとしていること。
Module レベルで State, Start, Next, Valueを定義している。
Nextはsig type state (* val filter : state -> state *) val start : state val next : state -> state val value : state -> int endなものを返す。あれ? ModuleレベルとCoreレベルでおんなじようなものを定義 してないですか?ってこと。Enrich Relationは
どこまでできる?
functorの適用を再帰的にできる (Moduleをパックして値化→functor適用のループを Coreで)
moduleに名前をいちいちつけなくてよい???
等価性判定とかは述べてない。eqtypeとか良くわかってないんですけど。 等価性判定ができるものじゃないらしい。package型の等価性は述べられている。
- - val a = [ structure struct val a = 1 end as sig val a : int end];; ! Toplevel input: ! val a = [ structure struct val a = 1 end as sig val a : int end];; ! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ! Compliance Warning: ! The phrase is an instance of the Moscow ML extension: ! <atexp> ::= [structure <modexp> as <sigexp>] ! which is not supported by the Definition of Standard ML. > val a = [structure ...] : [{val a : int}] - - a;; > val it = [structure ...] : [{val a : int}] - - val b = [ structure struct val a = 1 end as sig val a : int end];; ! Toplevel input: ! val b = [ structure struct val a = 1 end as sig val a : int end];; ! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ! Compliance Warning: ! The phrase is an instance of the Moscow ML extension: ! <atexp> ::= [structure <modexp> as <sigexp>] ! which is not supported by the Definition of Standard ML. > val b = [structure ...] : [{val a : int}] - - a;; > val it = [structure ...] : [{val a : int}] - - a = b;; ! Toplevel input: ! a = b;; ! ^ ! Type clash: expression of type ! [{val a : int}] ! cannot have equality type ''a
principal typeをもち
型が決定可能である観察日記風
contextの中に∃は入らない。∃をとって入れる。
contextから探してstructureをとってきたとき(pathの評価時)は∃φを付ける。
signatureのΛはcontextの中でも存在する。なにが抽象型 かを記録している。
( OnTwowards :> Stream ) の局面に注目
structure & signature
constraintはopaqueなもの(":>")のみ。(transparentなconstraint ":" は扱わない。Ocaml風)
SMLの二つの適用はsignatureの表現を共有するため!?
SMLではletは局所変数の名前づけで、fun,valはglobalな名前づけ!?First-Class ... の pack s as S の型づけ 規則の前提は 3行めまで SとS' が入れ替わっている。
stratificationがなくなっているとは?
Leroy .. stratified
functorはpathに対してのみ適用可能
Harper and Lillibridge .. amalgamation (not stratified)
static semantic objectはDefinition of Standard MLで使用されている。(がad hocであるらしい)
2つの流儀
文法的に表現可能なもの(つまりtype phrase)で表しきる方法
dependent typeを持ち込む
semantic objectを用いる方法
これをprogrammerが覚えるのか?
証明に影響しないか?
OOとの違い。
モジュールシステムは
シンプル。
継承はない
=> 階層構造をつくらなくてよい (signature matching)
類似
アクセス制限が可能
recordのsubtyping rule (enrich relation)
言語拡張必要か?を観察
レコードで structureを真似できないか?レコードとは!?
- 静的に決まる名前(ラベル)から値を連想する
- (あらかじめどのようなフィールドがあるかを宣言する) ← かならずしもそうではないようで..
> val it = {f = "hoge", g = "moge", h = "ge"} : {f : string, g : string, h : string}- type record = { f : string }; type record = {f:string} - type record2 = { f: string, g : int }; type record2 = {f:string, g:int} - fun get_f x = (#f x); stdIn:28.1-28.21 Error: unresolved flex record (can't tell what fields there are besides #f) - fun get_f (x:record) = (#f x); val get_f = fn : record -> string - fun get_ff (x:record2) = (#f x); val get_ff = fn : record2 -> string共通するフィールド名をもつレコードがあって良い。ここでは record1,record2。ただ、 レコードを受け取る関数は多相関数にならない!? (ほんとかなぁ fという名をもつレコード 全体を表す型の表現があったと思ったけれど)
参考
SML#
大堀先生の "A Polymorphic Record Calculus and Its Compilation" をもとに SMLを多相レコード型で拡張している。と思うが、makeできなかった....。挑戦してみる
(* いちいち作るものの型宣言 *) (* signatureに対応 *) type new_struct = { divisor : state -> int, filter : state -> state, (** state = .. typeはかけない **) start : state -> state, next : state -> state, value : state -> int } val sift s = { divisor = s.value s.start, filter = let rec sub state = if divides divisor ((#value s) state) then (sub (#next s state)) else state in sub end, start = filter (* of self *) }大体 recordの評価方法ってどんなんじゃ!?
- レコードは作るまえにフィールド名とその型の宣言をする。一方で、structureは あらかじめその型(signature)を宣言する必要はなく、デフォルトのsignatureがつく。
- フィールド同士に依存関係をもつことができない!? (this,self pointer...?)
- 型宣言は書けない
依存性をもてないのイメージ
> type depend = {data : string, print_data : unit -> unit} - #print_data { data = "takashi"; print_data = fn () => print data } ();; ! Toplevel input: ! #print_data { data = "takashi"; print_data = fn () => print data } ();; ! ^ ! Syntax error.ここで、 print_data に束縛できる値は unit -> unit 型である関数全体である。この print_data に束縛される関数がたまたま"近隣住人になった" dataの値をしるわけがない。 (closureに他のフィールドである data が入らない。)
todo
型のcompatibility
Λと∃で束縛される変数の意味。
変数重複を許していない(避けている!?)箇所
前例との比較
existential structureについて考えてみる
コンテキストにstructureが入る場合にこの∃による束縛は無くなる
入れる場合
参照する場合
c.f.) letで型多相、型環境内のtype schememosmlでみてみる
新しい型名が導入されたとか言う。globalに管理しているから∃でなくてもよいって ことかな?
structure Nest = struct structure Child = struct type t = int end :> sig type t end; end; > New type names: t structure Nest : {structure Child : {type t = t}} - structure Hoge = struct type t = int end :> sig type t end; > New type names: t/1 structure Hoge : {type t = t/1}
おまけ
signatureに書けるもの (というかstructureの中で書けるからsignatureで書ける) Ocaml
signature定義を要素として書ける
functorのsignature
# module A = struct module type S = sig type t end module F = functor(X:S) -> struct type u = T of X.t end end;; module A : sig module type S = sig type t end module F : functor (X : S) -> sig type u = T of X.t end end # module RA = (A: sig module type S end);; (* えっ!? *) module RA : sig module type S endSML(- mosml)
signatureはTop-levelでのみ書ける
functorもTop-levelでのみ
だからsignatureにはsignature定義やfunctorのsignatureといったものはない。Moscow ML
structure内にsignatureの定義を書けるが structureのsignatureには残らない
structure内にfunctor定義を書けてsignatureに残る(外からアクセス可能)
- structure A = struct signature S = sig type t end functor F (X:S) = struct datatype t = T of X.t end signature S = sig type t end end;; ! Toplevel input: ! signature S = sig type t end ! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ! Compliance Warning: ! The phrase is an instance of the Moscow ML extension: ! <strdec> ::= signature <sigbind> ! which is not supported by the Definition of Standard ML. ! Toplevel input: ! functor F (X:S) = struct datatype t = T of X.t end ! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ! Compliance Warning: ! The phrase is an instance of the Moscow ML extension: ! <strdec> ::= functor <funbind> ! which is not supported by the Definition of Standard ML. ! Toplevel input: ! signature S = sig type t end ! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ! Compliance Warning: ! The phrase is an instance of the Moscow ML extension: ! <strdec> ::= signature <sigbind> ! which is not supported by the Definition of Standard ML. > structure A : {functor F : !t. {type t = t}-> ?t/1.{datatype t = (t/1,{con T : t -> t/1}), con T : t -> t/1}}
Includemod.check_modtype_equiv
型をunifyするのに型Aと型Bとの等価性判定をしなければならない。等価性判定をどうするかが もっとも重要であるが、従来のmodule typeの比較と同様に行えばよい。
non-dependent typeとfirst-class structure
1.値(structure)が動的に切り替わるのに型がそれに依存してしまっては静的に型つけできない!?
semantic objectについての議論はP59(Chapter 2)
歴史
SOL
Quest
DL
XMLtranslucent sum (opaque型とmanifest型の指定が可能)
参考文献
Claudio V. Russo, First-Class Structures for Standard ML
The 1999 International Conference on Function Programming (ICFP)Mark Shields and Simon Peyton Jones. First-class Modules for Haskell
In the Ninth International Conference on Foundations of Object-Oriented Languages (FOOL 9), Portland, Oregon