データ型 プログラミング言語論 — 6-1 データ型 (data type) とは プログラミング言語において非常に重要 • ハードウェアからの抽象 • 記述性,可読性 • 信頼性,安全性 – 型検査による型誤りの検出 • 効率 – 型情報を用いた最適化 プログラミング言語論 — 6-2 型検査 型誤りを検出する • 静的な型検査 – コンパイル時,リンク時に検出 • 動的な型検査 – 実行時に検出 – 配列の添字範囲チェック等 • 強く型付けされた言語 – 型誤りが必ず検出される プログラミング言語論 — 6-3 変数の型宣言 • 明示的な型宣言 • 暗黙的な型宣言 – ML, Haskell, Scala 等の言語での型推論 • 変数に型のない言語 – Lisp, Prolog や多くのスクリプト言語では,変 数は型を持たない (setq x 123) (+ x 456) (setq x "abc") (+ x 456) ; エラー プログラミング言語論 — 6-4 型の構造 • 部分型 (部分範囲型) subtype INDEX is INTEGER range -10..10; type DAY is (MON, TUE, WED, THU, FRI, SAT, SUN); subtype WEEKDAY is DAY range MON..FRI; • 派生型 type YEAR is new INTEGER; • 多相型 – 型をパラメータに取る型 – Java 5 の Generics (parameterized types) プログラミング言語論 — 6-5 Java 5 の Generics • Java 2 以前 ArrayList の要素は任意の Object ArrayList list = new ArrayList(); list.add(new Integer(123)); Integer x = (Integer)list.get(0); /* cast が必要 */ • Java 5 ArrayList の要素の型を型パラメータで指定 ArrayList<Integer> list = new ArrayList<Integer>(); list.add(new Integer(123)); Integer x = list.get(0); /* cast は不要 */ プログラミング言語論 — 6-6 データ型の種類 • 原始型 (primitive types) – – – 数型,文字型 論理型 列挙型 (enum) • 集成型 (aggregate types),派生型 – – – – – – – – 配列型 文字列型 レコード型 (構造体,struct) 可変レコード型 (共有体,union) 集合型 リスト型 ポインタ型 関数型 プログラミング言語論 — 6-7 原始型 • 数型 • 文字型 – C や Java では整数として取り扱われる – Java では Unicode を用いる • 論理型 – C には存在しない.if (0 < x < 9) 等の誤 りが生じる • 列挙型 (enum) – C では整数として取り扱われるので安全でない – Java 5 で typesafe な列挙型が導入された プログラミング言語論 — 6-8 列挙型 C 言語では enum は単なる整数定数 enum day { MON, TUE, WED, THU, FRI, SAT, SUN }; int main() { enum day d; int x; d = SUN; x = SUN; printf("%d\n", d); } /* エラーとならない */ /* 6 が表示される */ Java 5 ではオブジェクト enum Day { MON, TUE, WED, THU, FRI, SAT, SUN }; public static void main(String[] args) { Day d; int x; d = Day.SUN; x = Day.SUN; /* エラー */ System.out.println(d); /* SUN が表示される */ } プログラミング言語論 — 6-9 配列型 • 要素の型はすべて同じ • Pascal では,整数や列挙型の部分範囲をインデッ クスとして利用可能 type a = array [-5..5] of integer; type b = array [MON..FRI] of integer; • C では配列の大きさはコンパイル時に定数でな ければならないが,Java では実行時に配列の大 きさを指定可能 • C では,配列名は配列の先頭要素へのポインタ 値を表す (sizeof の引数となる時等を除く). int a[SIZE]; p = a; /* p = &a[0] と同じ */ プログラミング言語論 — 6-10 文字列型 • C の場合 – 文字の配列として実現されており,プログラ マが最大長を宣言する必要がある (動的にメ モリ領域を確保することは可能) – 文字列終端に nul 文字 (’\0’) を置く必要が ある • Java の場合 – オブジェクトとして実現されており,処理系 が自動的に領域管理を行う – 文字列長も処理系が管理 プログラミング言語論 — 6-11 レコード型 • 直積構造 • C では構造体 (struct) struct t { int i; float f; int a[SIZE]; }; struct t s; struct t *p; s.i = 123; s.a[0] = 456; p = &s; p->i = 123; p->a[0] = 456; /* p->i は (*p).i と同じ */ プログラミング言語論 — 6-12 可変レコード型 (1) • メンバがメモリー上で同一領域を占める • C では共用体 (union) union t { int i; float f; }; union t u; u.i = 123; printf("%d\n", u.i); printf("%f\n", u.f); /* これは一種の型誤り */ プログラミング言語論 — 6-13 可変レコード型 (2) • どのメンバを利用しているかを表すタグフィー ルドを付けて用いることが多い • タグの値を動的に検査する言語もある enum tag { TAG_INT, TAG_FLOAT }; struct t { enum tag tag; union { int i; float f; } value; } s; s.tag = TAG_INT; s.value.i = 123; if (s.tag == TAG_INT) { printf("%d\n", s.value.i); } プログラミング言語論 — 6-14 集合型 (1) • Pascal で利用できるが,集合の要素数は 1 語の ビット数に制限される • ビット演算に対応する Pascal での例 type COLOR = set of (RED, GREEN, BLUE); var C, C1, C2: COLOR; C1 := [RED,GREEN]; C2 := [GREEN,BLUE]; C := C1 + C2; /* 和集合 */ C := C1 * C2; /* 積集合 */ C := C1 - C2; /* 差集合 */ if RED in C1 then /* 要素 */ .....; プログラミング言語論 — 6-15 集合型 (2) C で同様の事を実現する例 enum { RED=01, GREEN=02, BLUE=04 }; int c1, c2, c3; c1 = RED | GREEN; c2 = GREEN | BLUE; c = c1 | c2; c = c1 & c2; c = c1 & ~c2; if ((RED & c1) != 0) .....; /* /* /* /* 和集合 */ 積集合 */ 差集合 */ 要素 */ プログラミング言語論 — 6-16 リスト型 (1) • 関数型言語,論理型言語等で用いられる • Lisp では以下の関数を用いる – (car x): リスト x の先頭要素 – (cdr x): リスト x の先頭要素を除いた残り のリスト – (cons x y): リスト y の先頭に x を追加し たリストを作成 プログラミング言語論 — 6-17 リスト型 (2) (setq x ’(a (b c) d)) (car x) (cdr x) (cdr (cdr x)) ; a ; ((b c) d) ; (d) (cdr (cdr (cdr x))) (car (cdr x)) ; () ; (b c) (cons ’e x) (car (cons ’e x)) (cdr (cons ’e x)) ; (e a (b c) d) ; e ; (a (b c) d) • サスマンほか著 「計算機プログラムの構造と解釈 第二版」, ピアソン・エデュケーション,4600 円 プログラミングの様々な概念を Scheme を用いて解説した名著 プログラミング言語論 — 6-18 ポインタ型 • ハードウェアでのアドレスに相当する • 動的なデータ領域や再帰的な構造を表現するた めに用いられる • C ではスタック上のオブジェクトを指すことが 可能なため,特にバグを生じやすい (dangling pointer) char *readline() { char buffer[1000]; fgets(buffer, 1000, stdin); return buffer; } プログラミング言語論 — 6-19 関数型 • C では関数へのポインタを利用 • Lisp ではラムダ式で名前のない関数を記述できる (defun inc (x) (+ x 1)) (mapcar ’inc ’(1 2 3)) => (2 3 4) (mapcar (lambda (x) (- x 1)) ’(1 2 3)) => (0 1 2) • Scheme では変数の束縛環境を含めた関数クロー ジャと呼ばれるものを利用できる (define (make-func y) (lambda (x) (+ x y))) (define func (make-func 1)) (func 123) => 124 プログラミング言語論 — 6-20 多相型について (1) • 単相 (monomorphic) 関数,手続き,オペランドが一つの型だけを持つ • 多相 (polymorphic) 関数,手続き,オペランドが一つ以上の型を持つ – アドホック (ad-hoc polymorphism) 真の多相ではない – 汎用 (generic polymorphism) 無限の型に対して働く プログラミング言語論 — 6-21 多相型について (2) • アドホック – 多重定義 (overloading) それぞれの型に対して定義されている.例え ば,整数,浮動小数点数,文字列に対する+の 演算.強制型変換が行われることもある – 継承 (inheritance polymorphism) 派生型 (subtype) が基底型 (supertype) の演 算を継承する.オブジェクト指向言語で用い られる プログラミング言語論 — 6-22 多相型について (3) • 汎用 – パラメータ付き (parametric polymorphism) 型のパラメータを持つ ∗ C++の template 与えられた型ごとに別々の目的コードが 生成される ∗ Java の generics 単一の目的コードが生成される プログラミング言語論 — 6-23 多相型の例 (1) Java 5 での利用の例 List<Integer> list = new ArrayList<Integer>(); list.add(new Integer(123)); Integer x = list.get(0); /* cast 不要 */ Iterator<Integer> iter = list.iterator(); while (iter.hasNext()) { Integer y = iter.next(); /* cast 不要 */ } Map<String,Integer> map = new HashMap<String,Integer>(); map.put("abc", new Integer(456)); Integer z = map.get("abc"); プログラミング言語論 — 6-24 多相型の例 (2) Java 5 での定義の例 class Pair<T1,T2> { T1 first; T2 second; public Pair(T1 f, T2 s) { first = f; second = s; } public T1 first() { return first; } } public T2 second() { return second; } Pair<String,Integer> pair = new Pair<String,Integer>("abc", new Integer(123)); String x = pair.first(); プログラミング言語論 — 6-25 抽象データ型 (1) • 型をその構造によって定義するのでなく,操作に よって定義する • インターフェイスと実現を分離 – インターフェイスは可能な操作を規定 – 実現部分は隠蔽 (encapsulation) する • C では,インターフェイス部分をヘッダファイル に分離して記述するのが一般的 • Java では,分離するのではなく,公開部部分に public 修飾子,隠蔽部分に private 修飾子を用 いる プログラミング言語論 — 6-26 抽象データ型 (2) • スタック – push, pop ができる物 – 配列,リスト等の何で実現されているかは隠す プログラミング言語論 — 6-27
© Copyright 2024 Paperzz