プログラミング言語論 第12回 関数型プログラミング 情報工学科 篠埜 功.

Slides:



Advertisements
Similar presentations
プログラミング演習B ML編 第1回 2006/6/20 (通信コース) 2006/6/28 (情報コース) 住井 ~sumii/class/proenb2006/ml1/
Advertisements

プログラミング言語論 第10回(演習) 情報工学科 木村昌臣   篠埜 功.
(Rubyistのための) 超音速:ML入門
プログラミング演習II 2004年11月 30日(第6回) 理学部数学科・木村巌.
京都大学情報学研究科 通信情報システム専攻 湯淺研究室 M2 平石 拓
プログラミング言語としてのR 情報知能学科 白井 英俊.
Javaのための暗黙的に型定義される構造体
プログラミング入門2 第10回 構造体 情報工学科 篠埜 功.
プログラミング入門2 第10回 構造体 情報工学科 篠埜 功.
プログラミング言語論 第1回 情報工学科 篠埜 功.
型宣言 (Type Declarations)
プログラミング言語論 第1回 情報工学科 篠埜 功.
プログラミング言語論 第6回 型 情報工学科 篠埜 功.
第2回:Javaの変数と型の宣言 プログラミングII 2007年10月2日.
型宣言(Type Declarations)
プログラミング言語論 第4回 式の構文、式の評価
プログラミング言語論 第4回 手続きの引数機構 変数の有効範囲
条件式 (Conditional Expressions)
~sumii/class/proenb2010/ml4/
2007/1/11 山下 諒蔵 佐藤 春旗 前田 俊行 大山 恵弘 佐藤 秀明 住井 英二郎
ML 演習 第 7 回 新井淳也、中村宇佑、前田俊行 2011/05/31.
第3回 配列,構造体,ポインタ ~ データ構造について学ぶための基礎~
2007/6/5(通信コース)2007/6/6(情報コース) 住井
プログラミング言語論 第2回 情報工学科 篠埜 功.
~sumii/class/proenb2010/ml1/
プログラミング言語入門 手続き型言語としてのJava
プログラムの制御構造 選択・繰り返し.
PROGRAMMING IN HASKELL
暗黙的に型付けされる構造体の Java言語への導入
プログラミング言語論 第9回 Hoare論理の練習問題 手続きの引数機構 変数の有効範囲
精密工学科プログラミング基礎 第10回資料 (12/18実施)
アルゴリズムとプログラミング (Algorithms and Programming)
プログラミング入門2 第8回 ポインタ 情報工学科 篠埜 功.
PROGRAMMING IN HASKELL
プログラミング入門2 第11回 情報工学科 篠埜 功.
~sumii/class/proenb2009/ml1/
国立情報学研究所 ソフトウェア研究系 助教授/
 型推論1(単相型) 2007.
4.リスト,シンボル,文字列.
フロントエンドとバックエンドのインターフェース
プログラミング言語論 第9回 情報工学科 木村昌臣 篠埜 功.
コンパイラ 2011年10月20日
 型推論3(MLの多相型).
精密工学科プログラミング基礎Ⅱ 第5回資料 今回の授業で習得してほしいこと: 構造体 (教科書 91 ページ)
2007/6/12(通信コース)2007/6/13(情報コース) 住井
プログラミング入門2 第9回 ポインタ 情報工学科 篠埜 功.
Type Systems and Programming Languages
プログラミング入門2 第6回 関数 情報工学科 篠埜 功.
第14回 前半:ラムダ計算(演習付) 後半:小テスト
PROGRAMMING IN HASKELL
プログラミング言語論 第10回 情報工学科 篠埜 功.
~sumii/class/proenb2010/ml2/
~sumii/class/proenb2009/ml4/
アルゴリズムとデータ構造1 2009年6月15日
2006/7/18(通信コース)2006/7/26(情報コース) 住井
2006/6/27(通信コース)2006/7/5(情報コース) 住井
情報処理Ⅱ 第7回 2004年11月16日(火).
プログラミング言語論 第2回 篠埜 功.
PROGRAMMING IN HASKELL
~sumii/class/proenb2010/ml5/
コンパイラ 2012年10月11日
アルゴリズムとデータ構造 2010年6月17日
プログラミング入門2 第6回 関数 情報工学科 篠埜 功.
PROGRAMMING IN HASKELL
情報処理Ⅱ 2005年11月25日(金).
プログラミング入門2 第5回 配列 変数宣言、初期化について
 型理論の初歩 2007 fall.
情報処理Ⅱ 小テスト 2005年2月1日(火).
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
2007/6/26(通信コース)2007/6/27(情報コース) 住井
Presentation transcript:

プログラミング言語論 第12回 関数型プログラミング 情報工学科 篠埜 功

ML MLは関数型言語で、命令型の機能も持つ。(function-oriented imperative language) 関数型の特徴(Lispと同様): 関数が第一級の値(first class value) 式の一部で関数が生成できる 関数へ引数として関数を渡せる 関数の返り値として関数を返せる MLの型システムは最もきれいで表現力が高いと考えられている Lisp/Algol系言語の重要な概念を含んでいる このスライドではStandard MLを用いて説明する。その他の関数型言語としてはOCaml、Haskellなどがある。

MLの型システム MLの型システムは安全(safe) 型検査器が式がある型を持つと判定した場合、その式の評価が終わった時にその型の値を生成することが保証される。 (例)ある式が文字列へのポインタ型の場合、その式の値は文字列を保持しているメモリ領域を指すポインタであることが保証される。(解放された領域を指すポインタ(dangling pointer)や文字列以外の値を指すポインタにはならない。)

対話環境(interactive session) <式>; val it = <値の表示> : <型> (例) - 5+3-2; val it = 6 : int - it+3; val it = 9 : int - if true then 1 else 5; val it = 1 : int - 5=4; val it = false : bool

MLの式の評価(実行) 式は構文解析、型検査、コンパイルの後実行される。 式が構文エラーや型エラーだった場合、コードは生成されず、実行もされない。 (例)式if true then 3 else falseは構文エラーはないが、MLの型システムはthen partとelse partが同じ型を持つことを要求するので、型エラーとなる。 - if true then 3 else false; stdIn:5.1-5.26 Error: types of if branches do not agree [literal] then branch: int else branch: bool in expression: if true then 3 else false

宣言 val <id> = <exp>; val <id> = <値の表示> : <type> valはvalueの頭文字3文字。宣言が入力されると、右辺の式が評価され、左辺の識別子に束縛される。 (例) - val x = 7+2; val x = 9 : int - val y = x+3; val y = 12 : int - val z = x*y-(x div y); val z = 108 : int

(参考) MLでは/はreal型(浮動小数)の割り算に用いられる。 Cの暗黙の型変換のように、int型からreal型への型変換が自動的には行われない。 (例) - 9/12; stdIn:1.2-1.6 Error: operator and operand don't agree [literal] operator domain: real * real operand: int * int in expression: 9 / 12

関数宣言 fun <id> <arguments> = <exp>; val <id> = fn : <引数の型> -> <結果の型> (例) - fun f (x) = x+5; val f = fn : int -> int これは関数(int -> int型)をfに束縛する。 - val f = fn x => x+5; のように宣言することもできる。 fn x => x+5はラムダ式のλ x. x + 5に対応する。

代入について MLでは識別子の値は代入によって変更することができない。例えば、val x = 3と宣言されるとxの値は常に3である。(MLの宣言はconstantを導入する。)MLで代入可能な変数を宣言するにはreference cellを用いる。 (例) - val x = ref 3; val x = ref 3 : int ref - !x; val it = 3 : int - x:=4; val it = () : unit val it = 4 : int

CやPascalにおける識別子 CやPascalの識別子は、int型の変数は代入可能な変数であるが、関数宣言をした場合に関数名はconstantであり、代入によって別の関数に変更することはできない。つまりCやPascalでは型に応じてconstantかどうかが決まる。

型(type) 型は、値(value)の集合と操作(operation)の集合から成る。 型は、型式(type expression)を用いて表される。 (型式の定義) <type-exp> ::= <type-name> | <type-exp> -> <type-exp> | <type-exp> * <type-exp> | <type-exp> list | {<id>:<type-exp>,…,<id>:<type-exp>}

基本型(basic type) 値がatomicな場合、その型は基本型であるという。値がそれ以上分解できない場合その値はatomicであるという。 (例)集合{true, false}の値はatomicな値である。 基本型の値に対する操作は型毎に定義されており、等しさの比較などがある。 (例)2=2はtrue, 2≠2はfalse。

MLの基本型 unit型 bool型 () : unit 返り値の必要ない関数の返り値、引数の必要ない関数の引数に用いられる。(Cで言えばvoid型) bool型 true: bool, false : bool if式 if e1 then e2 else e3 においてe1はbool型、e2とe3は何らかの同じ型を持たなければならない。elseパートのないif式はない。 論理演算子andalso, orelse, notはCの&&, ||, !に相当する。

MLの基本型(続き) int型 string型 real型 0,1,2,..,-1,-2,… : int +, -, *, div : int * int -> int (これらは中置演算子) string型 ダブルクォートで囲んだ記号列 文字列連結演算子^ : string * string -> string (中値) real型 1.0, 2.0, 3.14159, 4.4444, … : real +, -, *はreal, intどちらにも適用可。(ただし左右が同じ型でなければならない) real関数でintからrealへの変換を行う。例えばreal(3)は3.0。MLは型推論を行うので、明示的な変換を行うのは仕方がない。

組(tuple)、直積型(product type) 2つの型A, Bの直積型A*Bは型Aの値と型Bの値の対から成る。 (例)(1, “one”)は整数1と文字列”one”から成る対である。 n個の型の直積A1*A2*…*Anは組(a1,a2,…,an)から成る(aiは型Aiの値, 1 ≤ i ≤ n)。 直積型に対する演算は、対の最初の要素と2番目の要素を取り出す関数であり以下のように定義される。 fun first (x,y) = x; fun second (x,y) = y; n個の直積型に対する演算も同様に定義される。

組(tuple)の例 対(pair)、3つ組(triple)、4つ組(quadruple)、… - (3, 4); (組の例) val it = (3,4) : int * int - (4, 5.5, true); val it = (4,5.5,true) : int * real * bool - ("Taro", "Jiro", 5); val it = ("Taro","Jiro",5) : string * string * int - #2 (3, 4); val it = 4 : int - #1 ("Taro", "Jiro", 5); val it = "Taro" : string (組の要素の取得例)

レコード(record) Cの構造体、Pascalのレコードに対応する。レコードは組と似ているが、各要素に名前がついているのが異なる。 (例) - {first_name="Donald", last_name="Knuth"}; val it = {first_name="Donald",last_name="Knuth"} : {first_name:string, last_name:string}

リスト(list) リストは有限の長さの要素の列である。 型A listはA型の要素のリスト全てから成る。 (例)int listは整数のリスト全てから成る。 リストの要素は [ と ] の間にコンマで区切って書かれる。空リストは[ ]あるいはnilと書かれる。 (例)[1,2,3]は3つの整数1,2,3のリストであり、[“red”, “white”, “blue”]は3つの文字列”red”, “white”, “blue”のリストである。 consは::で記述する。 (例) - 3::nil; val it = [3] : int list - 4::5::it; val it = [4,5,3] : int list

リスト(続き) Lispにおけるリストとは異なり、MLのリストは要素がすべて同じ型でなければならない。 - [1,2,3,4]; (例) val it = [1,2,3,4] : int list - [true,false]; val it = [true,false] : bool list - ["red","blue"]; val it = ["red","blue"] : string list - [fn x=>x+1, fn x=>x+2]; val it = [fn,fn] : (int -> int) list (例)

リストに対する操作 null(x) xが空リストならtrue, そうでなければfalse hd(x) リストxの最初の要素 tl(x) リストxの最初の要素を除いたリスト a::x 最初の要素がaで残りのリストがxのリスト (例)null [ ] はtrue (例)null [1,2,3]はfalse (例)[1,2,3] = 1::[2,3] = 1::2::[3] = 1::2::3::[ ] ::は右結合であり、1::2::[3]は1::(2::[3])と同じであり、 1::2::3::[ ]は1::(2::(3::[ ]))と同じである。

パターン(pattern) val宣言の左辺は識別子1つではなく、パターンを用いることができる。 val <pattern> = <exp>; <pattern> ::= <id>|<tuple>|<cons>|<record>|<constr> <tuple> ::= (<pattern>, …, <pattern>) <cons> ::= <pattern> :: <pattern> <record> ::= {<id>=<pattern>, …, <id>=<pattern>} <constr> ::= <id>(<pattern>,…,<pattern>) (注意)パターン中に同じ変数が2回以上現れてはいけない等の制約がある。(BNFでは表現できないので別途checkされる。) nilは<constr>であり、引数のない構成子である。

パターンの例 - val t = (1,2,3); val t = (1,2,3) : int * int * int - val (x,y,z) = t; val x = 1 : int val y = 2 : int val z = 3 : int - val a::b = [1,2,3]; val a = 1 : int val b = [2,3] : int list - val (a,b::c) = (1,[2,3]); val b = 2 : int val c = [3] : int list

パターンを用いた関数宣言 fun <id> <pattern> = <exp> |… | <id> <pattern> = <exp> のいずれかの形で宣言できる。 (例) - fun f (x,y) = x+y; val f = fn : int * int -> int - fun length nil = 0 | length (x::xs) = 1 + length xs; val length = fn : 'a list -> int (注意)上記の例のfは2引数関数のように見えるが、対を1つ引数にとる1引数関数である。

(続き) - length ["a","b","c"]; val it = 3 : int 関数lengthの宣言は2つの節からなり、上から順にパターンマッチングが行われる。引数がnilにマッチするとき(引数が空リストのとき)はlengthは0を返し、そうでない時はx::xsとパターンマッチングが行われる。 データ型を定義する場合はdatatype宣言を用いる。 (例)datatype tree = LEAF of int | NODE of (tree * tree) の宣言下で以下のような関数が定義できる。 - fun inTree(x,LEAF y)=x=y | inTree(x,NODE(y,z))=inTree(x,y) orelse inTree(x,z); val inTree = fn : int * tree -> bool