Title Here

Similar documents
PowerPoint プレゼンテーション

プログラミング基礎I(再)

PowerPoint プレゼンテーション

Microsoft PowerPoint - ProD0107.ppt

Microsoft PowerPoint - exp2-02_intro.ppt [互換モード]

Microsoft PowerPoint - ruby_instruction.ppt

Javaプログラムの実行手順

Microsoft PowerPoint - prog03.ppt

Programming D 1/15

Microsoft PowerPoint - 05.pptx

Boost.Preprocessor でプログラミングしましょう DigitalGhost

第 2 章インタフェース定義言語 (IDL) IDL とは 言語や OS に依存しないインタフェース定義を行うためのインタフェース定義言語です CORBA アプリケーションを作成する場合は インタフェースを定義した IDL ファイルを作成する必要があります ここでは IDL の文法や IDL ファイ

C プログラミング演習 1( 再 ) 2 講義では C プログラミングの基本を学び 演習では やや実践的なプログラミングを通して学ぶ

メソッドのまとめ

Microsoft PowerPoint Java基本技術PrintOut.ppt [互換モード]

Java 基礎問題ドリル ~ メソッドを理解する ~ 次のプログラムコードに 各設問の条件にあうメソッドを追加しなさい その後 そのメソッドが正しく動作することを検証するためのプログラムコードを main メソッドの中に追加しなさい public class Practice { // ここに各設問

メソッドのまとめ

Functional Programming

JavaプログラミングⅠ

基礎プログラミング2015

コンパイラ演習第 11 回 2006/1/19 大山恵弘 佐藤秀明 今回の内容 バリアント / レコード 表現方法 型付け パターンマッチ 型付け switch 文への変換 簡単な最適化 マッチング漏れ 以降のフェーズでの処理 発展 exhaustivenessinformation の利用 パター

基本情報STEP UP演習Java対策

Microsoft PowerPoint - chap10_OOP.ppt

Microsoft PowerPoint - ●SWIM_ _INET掲載用.pptx

Javaセキュアコーディングセミナー2013東京第1回 演習の解説

Slide 1

Functional Programming

Sort-of-List-Map(A)

スライド 1

始めに, 最下位共通先祖を求めるための関数 LcaDFS( int v ) の処理を記述する. この関数は値を返さない再帰的な void 関数で, 点 v を根とする木 T の部分木を深さ優先探索する. 整数の引数 v は, 木 T の点を示す点番号で, 配列 NodeSpace[ ] へのカーソル

バイオプログラミング第 1 榊原康文 佐藤健吾 慶應義塾大学理工学部生命情報学科

ML 演習 第 4 回

Prog2_12th

Microsoft PowerPoint - 計算機言語 第7回.ppt

<4D F736F F D20438CBE8CEA8D758DC F0939A82C282AB2E646F63>

Microsoft PowerPoint - lec10.ppt

文字列操作と正規表現

Taro-リストⅠ(公開版).jtd

スライド 1


Microsoft PowerPoint - prog04.ppt

Microsoft Word - no206.docx

fp.gby

論理と計算(2)

<4D F736F F D2091E63589F182628CBE8CEA8D758DC08E9197BF2E646F6378>

Taro-リストⅢ(公開版).jtd

Microsoft PowerPoint - CproNt02.ppt [互換モード]

memo

Microsoft PowerPoint pptx

Microsoft Word - Training10_プリプロセッサ.docx

ガイダンス

プログラミングD - Java

Microsoft PowerPoint ppt

Java講座

JAVA入門

た場合クラスを用いて 以下のように書くことが出来る ( 教科書 p.270) プログラム例 2( ソースファイル名 :Chap08/AccountTester.java) // 銀行口座クラスとそれをテストするクラス第 1 版 // 銀行口座クラス class Account String name

コンパイラ演習 第 7 回

intra-mart Accel Platform — IM-Repository拡張プログラミングガイド   初版  

C のコード例 (Z80 と同機能 ) int main(void) { int i,sum=0; for (i=1; i<=10; i++) sum=sum + i; printf ("sum=%d n",sum); 2

プログラミングI第10回

PowerPoint プレゼンテーション

PowerPoint プレゼンテーション

PowerPoint プレゼンテーション

PowerPoint プレゼンテーション

テキスト処理第 2 回 田中哲産業技術総合研究所情報技術研究部門 akira/textprocess/

Parametric Polymorphism

02: 変数と標準入出力

Microsoft Word - Cプログラミング演習(12)

情報工学実験 C コンパイラ第 2 回説明資料 (2017 年度 ) 担当 : 笹倉 佐藤

PowerPoint プレゼンテーション

02: 変数と標準入出力

6 関数 6-1 関数とは少し長いプログラムを作るようになると 同じ処理を何度も行う場面が出てくる そのたびに処 理を書いていたのでは明らかに無駄であるし プログラム全体の見通しも悪くなる そこで登場す るのが 関数 である 関数を使うことを 関数を呼び出す ともいう どのように使うのか 実際に見て

3,, となって欲しいのだが 実際の出力結果を確認すると両方の配列とも 10, 2, 3,, となってしまっている この結果は代入後の配列 a と b は同じものになっていることを示している つまり 代入演算子 = によるの代入は全要素のコピーではなく 先をコピーする ため 代入後の a と b は

JAVA入門

Java プログラミング Ⅰ 7 回目 switch 文と論理演算子 今日の講義講義で学ぶ内容 switch 文 論理演算子 条件演算子 条件判断文 3 switch 文 switch 文 式が case のラベルと一致する場所から直後の break; まで処理しますどれにも一致致しない場合 def

DVIOUT-exer

また 初期化について 以下のサンプルコードのように指定すれば 定義時に値を代入できます * オマケ配列は同名で複数個の箱を用意出来ます 同名ではありますが それぞれは別々の個体であるわけです また この複数個の変数は メモリ上に連続で確保されます 2. 文字と文字列 C 言語では文字と文字列は異なる

break 文 switch ブロック内の実行中の処理を強制的に終了し ブロックから抜けます switch(i) 強制終了 ソースコード例ソースファイル名 :Sample7_1.java // 入力値の判定 import java.io.*; class Sample7_1 public stati

人工知能入門

Microsoft PowerPoint pptx

第8回 関数

Microsoft PowerPoint - kougi9.ppt

JAVA とテンプレート

PowerPoint プレゼンテーション

Microsoft Word - no15.docx

Microsoft PowerPoint - prog08.ppt

Microsoft PowerPoint - PLT3.ppt

PowerPoint プレゼンテーション

CプログラミングI

Java知識テスト問題

Microsoft PowerPoint - C言語の復習(配布用).ppt [互換モード]

第9回 型とクラス

情報処理Ⅰ演習

(1) プログラムの開始場所はいつでも main( ) メソッドから始まる 順番に実行され add( a,b) が実行される これは メソッドを呼び出す ともいう (2)add( ) メソッドに実行が移る この際 add( ) メソッド呼び出し時の a と b の値がそれぞれ add( ) メソッド

デジタル表現論・第6回

とても使いやすい Boost の serialization

Microsoft PowerPoint - 5Chap15.ppt

コンピュータ工学講義プリント (7 月 17 日 ) 今回の講義では フローチャートについて学ぶ フローチャートとはフローチャートは コンピュータプログラムの処理の流れを視覚的に表し 処理の全体像を把握しやすくするために書く図である 日本語では流れ図という 図 1 は ユーザーに 0 以上の整数 n

画像ファイルを扱う これまでに学んだ条件分岐, 繰り返し, 配列, ファイル入出力を使って, 画像を扱うプログラムにチャレンジしてみよう

Microsoft PowerPoint - kougi10.ppt

Transcription:

型レベルプログラミングの会 2009/04/18 入門 typelevel!(d).programming k.inaba http://www.kmonos.net/

D の型レベル計算 ひとことでいうと だいたい C++ と同じ

D の型レベル計算 以上 ご静聴 ありがとうございました

まじめに説明 C++ と同じところ template と その特殊化 (specialization) で型レベル計算します 違うところ 細々と機能が足されてます

今日のおはなしの内容 1: D 言語の template とは 2: 型レベル計算のやり方 3: 応用 : Generic Enumerator もどき 4: 応用 : Path-Dependent Type もどき 基本はだいたい C++ と同じなので C++ と違う部分を中心に

1 : 入門編 D 言語の template の おおざっぱな説明

D 言語の template C++ の template クラスや関数をパラメタライズする D の template クラスや関数や型定義や変数宣言の集まり をパラメタライズ Ruby や OCaml の moduleに近い? C++ っぽく使うための略記法もあります

例 : モジュールっぽい使い方 template MyList(T) { class list_t { T car; list_t cdr; list_t nil() { return null; list_t cons( T a, list_t d ) { list_t x = new list_t; x.car = a; x.cdr = d; return x;

例 : モジュールっぽい使い方 template MyList(T) { class list_t { T car; list_t cdr; list_t nil() { return null; list_t cons( T a, list_t d ) { list_t x = new list_t; x.car = a; x.cdr = d; return x; MyList!(int).list_t lst = MyList!(int).cons(123, MyList!(int).cons(456, MyList!(int).nil));

例 : モジュールっぽい使い方 template MyList(T) { class list_t { T car; list_t cdr; list_t nil() { return null; list_t cons( T a, list_t d ) { list_t x = new list_t; x.car = a; x.cdr = d; MyList!(int).list_t lst = return x; MyList!(int).cons(123, mixin MyList!(int); MyList!(int).cons(456, MyList!(int).nil)); list_t lst = cons(123, cons(456, nil));

別の例 : 多相型 の実現 template max(t) { T max( T x, T y ) { if( x < y ) return y; else return x; int a = max!(int).max(10, 20); real b = max!(real).max(3.14, 2.72); string c = max!(string).max( foo, bar );

別の例 : 多相型 の実現 template max(t) { T max( T x, T y ) { if( x < y ) return y; else return x; 長すぎる!!! int a = max!(int).max(10, 20); real b = max!(real).max(3.14, 2.72); string c = max!(string).max( foo, bar );

略記法その 1 テンプレートのメンバが 1 つだけ テンプレート名とメンバ名が同じ なら. メンバ名 は省略してよい int a = max!(int)(10, 20); real b = max!(real)(3.14, 2.72); string c = max!(string)( foo, bar );

略記法その 2 関数テンプレートの場合 実際の引数からテンプレート引数が推論できるなら!( テンプレート引数 ) は省略してよい int a = max(10, 20); real b = max(3.14, 2.72); string c = max( foo, bar );

略記法その 3 template max(t) { T max( T x, T y ) { if( x < y ) return y; else return x; これも 冗長! 同名メンバ 1 つだけを持つ 関数テンプレートは もっと簡単に書ける

略記法その 3 template max(t) { T max( T x, T y ) { if( x < y ) return y; else return x; T max(t)( T x, T y ) { if( x < y ) return y; else return x;

クラステンプレートでも同様 class Stack(T) { 実装 Stack!(string) stk = ; template Stack(T) { class Stack { 実装 Stack!(string).Stack stk = ;

2 : 入門編 型レベル計算の やりかた ~alias と特殊化 ~

ちょっと寄り道 alias とは 型や変数やテンプレートの別名を定義する alias int 整数 ; // int の別名 整数 整数 n = 100; alias n えぬ ; // nの別名 えぬ えぬ = 200; // nに200が入る

エイリアステンプレート 1 個だけ alias を宣言したテンプレート を型レベル関数として使うことが多いで す template pointer_to(t) { alias T* type; pointer_to!(int).type p; // int* 型

エイリアステンプレート さらに 唯一の同名メンバは. メンバ名 を省略できる 規則を使うと template pointer_to(t) { alias T* pointer_to; pointer_to!(int) p; // int* 型 // 残念ながら のような略記はない // alias T* pointer_to(t);

特殊化 = 型レベルパターンマッチ 型に関する条件分岐 型パターンに使う型変数 パターン // T* という形の型が渡されたときだけ処理 template pointee(t : T*) { alias T pointee; pointee!(int*) n; // int 型 pointee!(real) r; // コンパイルエラー

ちょっと寄り道 Principal Template ( 特殊化されてないテンプレート ) の宣言が要らない template<typename T> struct pointee; // これ template<typename T> struct pointee<t*> { typedef T type; ; template pointee(t : T*) { alias T pointee;

定番の例 : 型リスト class Nil { class Cons(A, D) { alias Cons!(int, Cons!(real, Cons!(string, Nil))) MyList; この型リストの長さを計算する型レベル プログラムを書いてみよう!

定番の例 : 型リスト 解答 template length(_: Nil) { const length = 0; パターン 1: Nil だった時 パターン 2: Cons だった時 template length(a: Cons!(A,D), D){ const length = 1 + length!(d); [ これはひどい ] 型パターンに使う2 個目以降の変数はパターンの後ろに記述

static if 別解もっと手続き型チックに static if 文 を使う template len(t) { static if( is(t==nil) ) const len = 0; else static if( is(t A==Cons!(A,D),D) ) const len = 1 + len!(d);

型レベルプログラミングのための専用構文 static if( cond ) {body1 else {body2 コンパイル時条件分岐 is( type comparison ) 型が等しいかどうかの判定 型の種類 ( クラス? 関数? 等 ) 判定

型レベルプログラミングの ための専用構文 type func( )( ) if( 条件 ) T max(t)(t x, T y) if( comparable!(t) ) { return x<y? y : x; 比較演算ができるような型 T に ついてのみ max を定義 concept (C++) や型クラス (Haskell) のような分割型チェックはない (c.f. boost::enable_if)

型レベルプログラミングの typeof( 式 ) 式の型を得る is(typeof( 式 )) ための専用構文 typeof(123) n; // n の型は int 式が型エラーのとき false OK なら true T max(t)(t x, T y) if( is(typeof( valueof!(t) < valueof!(t))) ) { return x<y? y : x;

ここまでのまとめ C++ と同じく テンプレートと特殊化 ( パターンマッチ ) で計算を行います template foo( ){alias foo; static if 文や is 式のような より 普通の D に近い構文があります この式で型エラーが起きないなら のような変態的な分岐が可能

3 : 応用編 タプル と 汎用イテレータ

タプルって? Dでは いわゆる 型リスト が言語のプリミティブとして提供されています さっきのはあくまでサンプル D のタプル 型 ( など ) のリスト あくまでコンパイル時のみの概念 ML/Haskell/Python 等々の タプル とは別物

簡単な例 class NamedPoint { int x; int y; string name; // 引数 3 つ受け取って x,y,name に // そのままセットするだけの // コンストラクタが欲しい

汎用性のない解 class NamedPoint { int x; int y; string name; // 超手書き this( int x, int y, string n ) { this.x = x; this.y = y; this.name = n;

タプルを使った コピペで使い回せる解 class NamedPoint { int x; int y; string name; this( typeof(this.tupleof) xs ) { this.tupleof = xs; が引数なコンストラクタ の型 (int,int,string) this オブジェクトのメンバ変数のリスト (x,y,name)

ライブラリ化 class NamedPoint { int x; int y; string name; mixin SimpleConstructor; template SimpleConstructor() { this( typeof(this.tupleof) xs ) { this.tupleof = xs;

タプルは型ではなくて型リスト この関数は (A,B,C) と D を受け取る 2 引数関数ではなく void foo( TypeTuple!(A,B,C), D ); A,B,C,D を取る 4 引数関数 T でタプルパラメタ void printf(ts )(string fmt, TS xs); 2 引数関数ではなく可変個引数関数

応用例 : Generic Enumerator データ構造から全自動でイテレータを作る! http://www.kmonos.net/wlog/80.html#_1008071221 の簡単バージョン 全要素に関数適用!! class List(T) { T car; List!(T) cdr; List!(char) lst = ; each( lst, (char c){writeln(c););

each を List 専用にすれば簡単 再帰的にデータをたどるだけ void each(t,f)( List!(T) lst, F fn ) { if( lst!is null ) { fn( lst.car ); each( lst.cdr, fn );

応用例 : Generic Enumerator えーマジ List 専用!? キモーイ class BinTree(T) { T value; BinTree!(T) left; BinTree!(T) right; List 専用が許されるのは小学生までだよねー BinTree!(real) bt = ; each( bt, (real r){ writeln(i); );

要は 渡されたものが List でも BinTree でも 渡されたもののフィールド全部 を取ってこれれば良い あと 型がわかれば良い T なら関数適用 Foo!(T) なら再帰的に潜る という条件分岐に型情報が必要

実装 void each(t, alias Cont, F) (Cont!(T) cont, F fn ) { if( cont!is null ) foreach(field; cont.tupleof) static if( is(typeof(field)==t) ) fn( field ); else static if ( is(typeof(field)==cont!(t)) ) each( field, fn );

こまかい拡張 (1) コンテナのクラスが直接再帰すると思ったら大間違いだ! Class Tree(T) { class Node { T value Node[] children; Node root; Cont!(T) を見つけたら再帰的に じゃなくて メンバ ( のメンバ )* に T があるなら再帰的に じゃないとまずい

そのように実装する void each_impl(t, X, F)( X x, F fn ){ static if( exists!(t).inside!(x) ) static if( is(x == T) ) fn( x ); else if( x!is null ) static if( is(x E == E[]) ) foreach(elem; x) each_impl!(t)(elem,fn); else foreach(field; x.tupleof) each_impl!(t)(field,fn); void each(t, alias C, F)(C!(T) c, F fn) { each_impl!(t)(c, fn);

型レベル計算 exists!(t).inside!(x) X を再帰的にたどりながら T があるかチェック ただし無限ループしないように 一度たどった型は覚えておく ( グラフの深さ優先探索 ) template exists(t) { template inside(x) { const inside = rec!(x).value; template rec(x, Visited...) { static if( indexof!(x, Visited)!=-1 ) const value = false; else 再帰的に X.tupleof をたどるコード

こまかい拡張 (2) class AVLTree(T) { int height; AVLTree!(T) left; T value; AVLTree!(T) right; AVLTree!(int) set = ; each( set, (int n){ writeln(n); ); 要素の型 int が内部データの型と一致する時だけが問題! AVLTree!(real) でも AVLTree!(string) でも問題ないのに!! AVLTree!(int) の中の int を列挙すると height まで表示されてしまう!!!!!

そりゅーしょん! AVLTree!( 内部データに使われない型 ) なら問題ないなら AVLTree!( 内部データに使われない型 ) を使えばいいじゃない

小技 : Shadow Type void each_impl(st, SX, X, F)( X x, F fn ){ static if( exists!(st).inside!(sx) ) static if( is(sx == ST) ) fn( x ); else if( x!is null ) static if( is(sx SE == SE[]) ) foreach(elem; x) 型レベルでは C!(ShadowT) のなかの ShadowT を探す 実行時は C!(T) の中の T each_impl!(st,se)(elem,fn); else foreach(i,field; x.tupleof) each_impl!(st,typeof(sx.tupleof[i])) (field,fn); void each(t, alias C, F)(C!(T) x, F fn) { class ShadowT { each_impl!(shadowt,c!(shadowt))(x, fn);

いろいろ細かい Q&A Shadow Type について Q: コンテナが特殊化されてる場合は? (C++ の vector<bool> の中の bool の位置は vector<st> の中の ST の位置と違う!) A: コンテナを特殊化するな! Q: コンテナが if 制約を使ってる場合は? (class AVLTree!(T) if( comparable!(t) ) { ) A: class ShadowT { T t; alias t this; でだいたい突破できます

いろいろ細かい Q&A Generic Enumerator 全般 Q: データ型のフィールドが private だったら? A: tupleof は private を完全無視する超仕様 Q: データ型がオブジェクト指向的に多態で実装されてる場合の扱いは?( class Tree(T){ interface Node{ ; Node root; ) A: ごめん これは無理!>< Q: 双方向リストを渡すと無限ループしない? A: ごめん これも無理!><

4 : 応用編 alias 引数 と パス依存型もどき

さまざまな引数 型 レベルというかどうか微妙なんですが D の template は 引数に色々とれます 型 値 ( 整数 浮動小数点数 文字列 ) テンプレート alias to グローバル / ローカル / メンバ変数 グローバル / ローカル / メンバ関数 無名関数リテラル

寄り道 : 値パラメタ フィボナッチとか書けるんですが template fib(int n) { static if( n<=1 ) const fib = 1; else const fib = fib!(n-1)+fib!(n-2); int array[fib!(10)]; // int array[89]; と同じ

寄り道 : CTFE コンパイル時でも普通の関数を呼べるので 計算だけなら普通はそっちで書きます int fib(int n) { return n<=1? 1 : fib(n-1)+fib(n-2); int array[fib(10)]; 副作用のない (& オブジェクト等を使わない ) 関数が 定数が必要な文脈で使われていると定数に畳み込むことを保証

それはともかく alias 引数の話 alias を引数にとれます void setter(alias x)(typeof(x) p) { x = p; class Foo { private int n; alias setter!(n) set_n; これを使って遊んでみましょう

突然ですが 僕が C++ でよくやるバグ vector<int> v = someprogram ; for_each(v.begin(), v.end(), f); vector<int> u = someprogram ; for_each(u.begin(), v.end(), f);

iterator: 凄く適当な説明 コンテナ中の位置を指すオブジェクト * で 指してる要素を get ++ で 次の要素を指すようにする c.begin() で先頭, c.end() で末尾が取れる void for_each (Ite,F)(Ite from, Ite to, F fn) { while( from!= to ) { fn( *from ); ++from;

再掲 : 僕が C++ でよくやるバグ v.end() と u.end() が 同じ型なのが悪い vector<int> v = someprogram ; for_each(v.begin(), v.end(), f); vector<int> u = someprogram ; for_each(u.begin(), v.end(), f);

そりゅーしょん alias 引数! class iterator(alias cont) { 実装は略 iterator!(cont) begin(alias cont)() { return new iterator!(cont)( cont.begin() ); // end も同様

そりゅーしょん これならコンパイル時に型エラー vector!(int) v = someprogram ; vector!(int) u = someprogram ; for_each(begin!(u), end!(v), f); こっちは iterator!(u) 型 こっちは iterator!(v) 型

End まとめ テンプレートとパターンマッチによる型レベル計算 static if や is 式など 型レベル処理専用構文.tupleof のようなコンパイル時リフレクション 型や整数の他に 変数への alias も型レベルで扱える 何かもっと面白いことができそう