PROGRAMMING IN HASKELL

Slides:



Advertisements
Similar presentations
アルゴリズムとデータ構造 第2回 線形リスト(復習).
Advertisements

基本情報技術概論 I 演習(第5回) 埼玉大学 理工学研究科 堀山 貴史
プログラミング演習II 2004年11月 30日(第6回) 理学部数学科・木村巌.
情報・知能工学系 山本一公 プログラミング演習Ⅱ 第4回 配列(2) 情報・知能工学系 山本一公
プログラミング基礎I(再) 山元進.
コンパイラ 2011年10月17日
プログラミング言語としてのR 情報知能学科 白井 英俊.
Relaxed Dependency Analysis
ソフトウェア基礎科学 授業資料: 論理関係(logical relations)のお話
プログラミングパラダイム さまざまな計算のモデルにもとづく、 プログラミングの方法論 手続き型 関数型 オブジェクト指向 代数 幾何.
データ構造とアルゴリズム 第10回 mallocとfree
はじめに 教科書 プログラミングHaskell Graham Hutton (著), 山本 和彦 (翻訳) オーム社、全 232 ページ
型宣言 (Type Declarations)
型宣言(Type Declarations)
情報処理Ⅱ 2005年12月9日(金).
香川大学工学部 富永浩之 情報数学1 第2-1章 合同式の性質と計算 香川大学工学部 富永浩之
データ構造とアルゴリズム 分割統治 ~ マージソート~.
条件式 (Conditional Expressions)
プログラミング演習Ⅰ 課題2 10進数と2進数 2回目.
コンパイラ 2012年10月15日
ML 演習 第 7 回 新井淳也、中村宇佑、前田俊行 2011/05/31.
プログラミング言語論 第12回 関数型プログラミング 情報工学科 篠埜 功.
データ構造と アルゴリズム 第十一回 理工学部 情報システム工学科 新田直也.
プログラミング基礎a 第8回 プログラムの設計 アルゴリズムとデータ構造
PROGRAMMING IN HASKELL
4 ソフトウェア工学 Software Engineering 抽象データ型 ABSTRACT DATA TYPE.
プログラミング論 関数ポインタ と 応用(qsort)
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
PROGRAMMING IN HASKELL
第10回関数 Ⅱ (ローカル変数とスコープ).
PROGRAMMING IN HASKELL
アルゴリズムとプログラミング (Algorithms and Programming)
PROGRAMMING IN HASKELL
前回の練習問題.
6. リスト処理関数の設計(発展版) プログラミング論 I.
お仕事にまったく役にたたない内容のコードレビューやりたいと思います。
アルゴリズムとデータ構造1 2005年7月5日
アルゴリズムとプログラミング (Algorithms and Programming)
Cプログラムの理解を 支援するナビゲーション機能
関数の再帰呼び出しとは ハノイの塔 リダイレクト レポート課題
プログラミング基礎a 第8回 プログラムの設計 アルゴリズムとデータ構造
プログラミング 4 整列アルゴリズム.
書き換え型プログラムの生成・検証 研究課題:適切な実行戦略を効率よく探索する、 より自動化された手続きの実現 書き換え型プログラム
4.リスト,シンボル,文字列.
知能情報システム特論 Introduction
11.再帰と繰り返しの回数.
プログラミング言語論 第9回 情報工学科 木村昌臣 篠埜 功.
アルゴリズムとデータ構造1 2006年7月11日
15.cons と種々のデータ構造.
プログラミング基礎a 第6回 C言語によるプログラミング入門 配列と文字列(その2)
15.1 文字列処理の基本 15.2 文字列処理用ライブラリ関数
統計ソフトウエアRの基礎.
アルゴリズムとプログラミング (Algorithms and Programming)
アルゴリズムとデータ構造1 2006年6月23日
~sumii/class/proenb2010/ml2/
香川大学創造工学部 富永浩之 情報数学1 第2-1章 合同式の性質と計算 香川大学創造工学部 富永浩之
2006/7/18(通信コース)2006/7/26(情報コース) 住井
~sumii/class/proenb2009/ml6/
5. 任意長の合成データ:リスト プログラミング論I.
PROGRAMMING IN HASKELL
Eijiro Sumii and Naoki Kobayashi University of Tokyo
~sumii/class/proenb2010/ml5/
プログラミング入門2 第6回 関数 情報工学科 篠埜 功.
PROGRAMMING IN HASKELL
Haskell Programming Language
データ構造と アルゴリズムI 第三回 知能情報学部 新田直也.
計算技術研究会 第5回 C言語勉強会 関数(function)を使う
プログラミング演習II 2003年10月29日(第2,3回) 木村巌.
オブジェクト指向言語論 第六回 知能情報学部 新田直也.
Presentation transcript:

PROGRAMMING IN HASKELL Chapter 6 - Recursive Functions 再帰関数 愛知県立大学 情報科学部 計算機言語論(山本晋一郎・大久保弘崇、2011年)講義資料 オリジナルは http://www.cs.nott.ac.uk/~gmh/book.html を参照のこと

factorial は、任意の整数 n を、 1 から n の整数の積に写像する イントロダクション これまで見てきたように、多くの関数は他の関数を利用して定義できる factorial :: Int  Int factorial n = product [1..n] factorial は、任意の整数 n を、 1 から n の整数の積に写像する

式は、関数をその引数に適用する手続きにより、段階的に評価される 例: factorial 4 product [1..4] = product [1,2,3,4] = 1*2*3*4 = 24 =

再帰関数(Recursive Functions) Haskell では、自分自身を用いて関数を定義できる。 そのような関数を再帰的(recursive)と呼ぶ。 factorial 0 = 1 factorial n = n * factorial (n-1) n+kパターン: factorial (n+1) = (n+1) * factorial n factorial は 0 を 1 に写像し、その他の正の整数を、その値×1つ小さい値のfactorial に写像する

For example: = = = = = = = factorial 3 3 * factorial 2 3 * (2 * (1 * 1)) = 3 * (2 * 1) = 3 * 2 = = 6

factorial 0 = 1 は 1 が乗法の単位元なので適切である: 1 * x = x = x * 1 注意: factorial 0 = 1 は 1 が乗法の単位元なので適切である: 1 * x = x = x * 1 0 より小さい整数に対して、基底ケースに到達できないため発散する: > factorial (-1) Error: Control stack overflow

再帰が役に立つ理由 factorial のように、他の関数(例えば product)を利用して定義するとより簡潔に定義できる関数もある しかし、以降の章で分かるように、自分自身を利用して自然に定義できる関数も多い 再帰を用いて定義した関数の性質は、単純かつ強力な数学的帰納法を用いて証明できる(13章)

product は空リストを 1 に写像し、非空リストを、 先頭要素×残りのリストのproduct に写像する リストに対する再帰 再帰は、整数だけに限られるのではなく、リスト関数にも使える product :: [Int]  Int product [] = 1 product (n:ns) = n * product ns product は空リストを 1 に写像し、非空リストを、 先頭要素×残りのリストのproduct に写像する

For example: = = = = = product [2,3,4] 2 * product [3,4] 2 * (3 * (4 * 1)) = 24 =

length は空リストを 0 に写像し、非空リストを、 残りのリストのlengthより1つ大きな値 に写像する product と同じ再帰パターンで、リストの長さを返す関数を定義する length :: [a]  Int length [] = 0 length (_:xs) = 1 + length xs length は空リストを 0 に写像し、非空リストを、 残りのリストのlengthより1つ大きな値 に写像する

For example: = = = = = length [1,2,3] 1 + length [2,3] 1 + (1 + (1 + 0)) = 3 =

同じ再帰パターンで、リストを反転する関数を定義する reverse :: [a]  [a] reverse [] = [] reverse (x:xs) = reverse xs ++ [x] reverse は空リストを空リストに写像し、非空リストを、 (残りのリストのreverse)と(先頭要素だけのリスト) を連結したリスト に写像する

For example: = = = = = reverse [1,2,3] reverse [2,3] ++ [1] (([] ++ [3]) ++ [2]) ++ [1] = [3,2,1] =

複数の引数 複数の引数を取る関数も再帰的に定義できる 例えば: 2 つのリストの要素同士を組にする: Zipping the elements of two lists: zip :: [a]  [b]  [(a,b)] zip [] _ = [] zip _ [] = [] zip (x:xs) (y:ys) = (x,y) : zip xs ys

リストの先頭から n 要素を取り除く: 2 つのリストを結合する: drop :: Int  [a]  [a] drop 0 xs = xs drop n [] = [] drop n (_:xs) = drop (n-1) xs n+kパターン: drop (n+1) [] = [] drop (n+1) (_:xs) = drop n xs 2 つのリストを結合する: (++) :: [a]  [a]  [a] [] ++ ys = ys (x:xs) ++ ys = x : (xs ++ ys)

クイックソート 整数リストを整列するクイックソートのアルゴリズムは、2 つの規則で定式化される: 空リストはソート済み 非空リストのソートは以下の 3 つのリストを連結したリスト (残りのリスト中の先頭要素以下の要素)をソートしたリスト 先頭要素のみのリスト (残りのリスト中の先頭要素より大きな要素)をソートしたリスト

再帰を用いて仕様を直接的に実装に変換できる: qsort :: [Int]  [Int] qsort [] = [] qsort (x:xs) = qsort smaller ++ [x] ++ qsort larger where smaller = [a | a  xs, a  x] larger = [b | b  xs, b  x] 注意: 他のプログラミング言語と比べて、おそらく最も簡潔な実装!

例 (qsort を q と省略): q [3,2,4,1,5] q [2,1] ++ [3] ++ q [4,5] q [1] q [] ++ [2] ++ q [] q [5] ++ [4] ++ [1] [] [] [5]

相互再帰 2 つ以上の関数が、お互いを参照し合う even, odd :: Int -> Bool even 0 = True even n = odd (n – 1) odd 0 = False odd n = even (n – 1) 実際の定義(上の定義は非効率) even, odd :: (Integral a) => a  Bool even n = n `rem` 2 == 0 odd n = not (even n) rem は習っていないので mod と考える

再帰の秘訣(product) 型を定義する(数値リストの要素の積を求める) product :: [Int]  Int 場合分けをする product [] = product (n:ns) = 簡単な方を定義する product [] = 1 product (n:ns) = 複雑な方を定義する product [] = 1 product (n:ns) = n * product ns 一般化し単純にする product :: Num a => [a]  a

再帰の秘訣(drop) 型を定義する(リストの先頭から n 要素を取り除く) drop :: Int -> [a]  [a] 場合分けをする drop 0 [] = drop n [] = drop 0 (x:xs) = drop n (x:xs) = 簡単な方を定義する drop 0 [] = [] drop 0 (x:xs) = x:xs drop n [] = [] 省略すれば実行時エラー 複雑な方を定義する drop n (x:xs) = drop (n-1) xs 一般化し単純にする drop :: Integral b => b  [a]  [a] drop 0 xs = xs drop n (_:xs) = ...

まとめ(6章) 再帰関数 相互再帰: 2 つ以上の関数が、お互いを参照し合う リストに対する再帰 自然な定義 数学的帰納法との好相性 相互再帰: 2 つ以上の関数が、お互いを参照し合う リストに対する再帰 再帰の秘訣: 5 段階の工程 型定義、場合分け、基底部、再帰部、一般化 factorial 0 = 1 factorial n = n * factorial (n-1) product [] = 1 product (n:ns) = n * product ns

問題 product に関する再帰の秘訣(6.6節、p.66)において、product [] = 1 と定義する理由を、”1 は乗法の単位元だから” としている。これを解説せよ。