Document

プログラミング論I
工学部2015年度 – プログラミング論I – 2015年
度前期 (廣川)
工学部大講義室(月曜1,2限目)
プログラミング論I
•
•
•
•
2年生前期:毎週月曜日1,2限目
目標:プログラムの基本設計法を習得
使用プログラミング言語:Scheme (後述)
単位取得:講義時の平常点+試験
– 出席点:10点,演習課題:20点,試験:70点
なぜプログラミングを学習するか
右下図:http://www.kkr.mlit.go.jp/river/keyword/images/03_01.jpgより
• 今やコンピュータは社会基盤の一部
– コンピュータソフトウェアに関する素養は必須
• コンピュータはデータを形式的(機械的)に処理
– 特定の言語によらず、データおよびその処理手順(プログラム)を論
理的に記述する(というプログラミング)能力は重要
その際には
• テクニックよりまず基本的な考え方を重視
– 問題分析、問題解決の技術
プログラミングは,この訓練になる
プログラム設計法(レシピ)
プログラム設計レシピ:問題解決過程のガイド
1.
2.
3.
4.
5.
6.
問題の解析とデータの定義
規約、目的、結果の記述とヘッダ作成
例題を用いたプログラムの振舞の例示
プログラムテンプレート、レイアウトの作成
テンプレートを完全な定義に変換
テストを通してエラーの発見
各ステップで中間生成物をチェック
(具体的な適用法や設計ごとのバリエーションは後述)
ソフトウェア開発と言語
• ソフトウェア開発(抽象レベルでは言語非依存):
– 物理システムの開発と同様きちんとした抽象化、設計法
– 物理法則のような制約がない→論理的正しさが特に重要
• 具体的実現:目的に適した言語(モデル)を選択
– モデル: 式、関数 / 手続き、副作用 / オブジェクト指向 等
– 目的:科学技術計算、事務処理、システムソフト、DBなど
• 本講義:基本的 「式、関数」 をベースとした言語
– Scheme という言語を使う
Scheme の特徴
• 関数型: 数学体系λ計算が基礎
– 式(関数)でプログラムを構成、式の簡約で計算が進む
• 紙と鉛筆(頭の中)でもプログラム実行過程が追える
• インタプリタ型処理系
– 初学者にも優しい(本質が埋もれがちな作業が少ない)
• 見た目としては演算子が前置記法で括弧が多い
– プログラムの基本単位である式を括弧で囲む
– 式の構成要素にまた式を持ち得る(括弧の入れ子)
例 4×2 + 4÷2 の表記とその計算過程:
(+ (* 4 2 ) (/ 4 2)) → (+ 8 (/ 4 2)) → (+ 8 2) → 10
Scheme についての参考資料
• 参考書
– [この講義] M. Felleisen et al., "How to Design Programs",
MIT Press (Web版 http://www.htdp.org/)
– [Scheme言語仕様] ケント ディヴィグ (村上雅章 訳), "プログ
ラミング言語SCHEME", ピアソン・エデュケーション
– [言語として Scheme を用いる他の著名な講義用テキスト]
サスマン他 (和田英一訳), "計算機プログラムの構造と解
釈", ピアソン・エデュケーション
プログラミング論Iの予定
• 前半:データに着目したプログラム開発の基本
•
•
•
•
数と数式、プログラムと実行過程、エラー
変数と関数、条件、プログラム設計法によるプログラム作成
様々なデータ(atomic/複合データ)およびその処理
任意長データと処理(リストと再帰処理プログラム)
• 後半:プログラミングに関するより高度な話題
•
•
•
•
•
設計の抽象化
値としての関数を使った抽象化 (高階関数)
再帰のバリエーション
知識の蓄積(アキュムレータ)
学習成果を使った様々な例題
• 非関数的なプログラミング
• 副作用(代入)、状態更新、外界との入出力
プログラミング論Iの進め方
• 「情報処理演習II」とゆるやかに連動
– プログラミング論I → 講義(例題を交えた説明)
• レシピ(設計のガイド)や例(理解の促進)を重視
• 講義資料などはすべて WWW で公開
http://matu.cc.kyushu-.ac.jp/~hirokawa/Programming/
Racket (Scheme処理系)
• http://download.racket-lang.org/
自分のPCに合う物を
選択してください
DrRacketの起動画面
Language
Choose
Language
プログラムの記述(1/2)
(+ 1 2)
(* 3 4)
(/ 5 6)
(- 7 8)
3
12
0.83
-1
この画面にプログラムを
書いて,RUNを押す
式の値が,
下の画面に現れる
プログラムの記述(2/2)
;; 1 dollar is 121.77 yen
;; d dollars is 121.77*d yen
;; d2y: number -> number
;; (d2y 3) should return 121.77*3=365.31
(define (d2y d)
関数定義の例
(* 121.77 d))
(d2y 3)
365.31
この画面にプログ
ラムを書いたら,
Enterを押す
この画面にプログラムを
書いたら,RUNを押す
C言語での定義
の例
#include <stdio.h>
double d2y(double d){
return (121.77*d);
}
int main(){
double d;
Visual Studio
printf(“d=“);
の場合
scanf_s("%lf", &d);
printf("%f\n", d2y(d));
return (0);
}
1. Scheme の式とプログラム
数、式、プログラムと実行過程、エラー
本日の内容
•
Scheme プログラムとその処理系の概要
•
Scheme の簡単な式
•
Scheme の簡単な関数
•
プログラムの実行過程
•
エラー
Scheme プログラム
データを処理(および入/出力)する手順の記述
• データ:
– 単体(atomic)データ
– 複合(compound)データ
複数のデータで構成
(固定サイズ、任意サイズ)
• 処理:
– 基本(primitive)演算・関数
– 既存の関数を部品として使う関数
対象問題を解くため,
これらを使った解決
手順を書く:
→ プログラミング
(本講義は基礎)
Scheme の実行イメージ
計算手順をSchemeで記述
作成・保存済の Scheme
プログラムの呼出も可能
コンピュータ上のインタプリタ
(解釈・実行ソフト)
計算が行われ,結果の表示
実行結果
参考:コンパイラ型のC言語
手順をC言語で記述
コンピュータ上の
コンパイラ
(翻訳ソフト)
実行可能形式に変換
コンピュータ上で実行
実行結果
Scheme の文法(基本レベル)
プログラミング言語も言語:語彙を文法に従って書き並べる
語彙
• 変数
• 定数:数、記号、真偽値
5 -5 0.5 'a true など
• primitive演算子
+ - * / remainder quotient
max min abs sqrt expt
log sin cos tan など
文法
• 式
– 定数、変数、
式、(演算子 式…)
基本的に前置記法
• 定義
– (define (変数…) 式)
これ以外にもあるが,適宜授業で説明
Scheme の式の例 - 四則演算 • (+ 5 5)
• (+ -5 5)
負の数も扱える
• (+ 0.5 0.5) 実数も扱える
• (- 5 5)
• (* 3 4)
• (/ 8 12)
+ - * / などが使える
* は掛算、 / は割算
処理系(DrRacket)での実行結果の例
入力を促す「プロンプト」
計算したい式
計算結果
式を入力すると,計算が行われ、
結果が表示される。 (処理系の
DrRacketの詳細は基礎演習で)
Scheme の式の例 - 各種の演算 • (remainder 100 15) ;; 100 を 15 で割った剰余(=10)
• (quotient 100 15) ;; 100 を 15 で割った商(=6)
• (max 3 5)
;; 3, 5 の大きい方 (=5)
• (min 3 5)
;; 3, 5 の小さい方 (=3)
• (abs -10)
;; -10 の絶対値 (=10)
実行結果の例
処理系では式を入力すると,
計算が行われて表示される
Scheme の式の例 -入れ子の式と括弧 (3  5) * (30 / 10)
( 2  2) *
2
• Scheme 言語で書くと:
(* (+ 2 2)
(/ (* (+ 3 5)
(/ 30 10))
2))
Scheme の式
括弧の意味
(3  5) * (30 / 10)
( 2  2) *
2
(* (+ 2 2) (/ (* (+ 3 5) (/ 30 10)) 2))
括弧が,計算の「単位」を表現している。
優先順位が高い単位から先に括弧で括る。
計算過程
最初に最内のカッコで括られた式を数に簡約、
引き続き次の入れ子の層の計算を続ける
(* (+
= (* 4
= (* 4
= (* 4
= 48
2 2) (/ (* (+ 3 5) (/ 30 10)) 2))
(/ (* 8 3) 2))
(/ 24 2) )
12)
左から右に,簡約が進む
Scheme式の形式: (operation A ... B)
計算規則:A...B が全て値ならoperationは計算可能。
そうでなければA...Bのうち値でないものをまず値に
練習1:Scheme 式
次の計算を行う Scheme の式を書き、結果も示せ
5+5
-5 + 5
3*4
8 / 12
3 + 4.5
(2 + 2) * (((3 + 5) * (30 / 10)) / 2)
>(+ 5 5)
10
>(+ -5 5)
0
>(* 3 4)
12
>(/ 8 12)
2/3
>(+ 3 4.5)
7.5
>(* (+ 2 2) (/ (* (+ 3 5) (/ 30 10)) 2))
>(* 4 (/ (* (+ 3 5) (/ 30 10)) 2))
>(* 4 (/ (* 8 (/ 30 10)) 2))
>(* 4 (/ (* 8 3) 2))
>(* 4 (/ 24 2))
>(* 4 12)
48
プログラムの構成要素:変数定義
ものには名前をつけることができる(定義)
通常、プログラムは数多くの定義からなる
• 関数定義:主関数、補助関数(後述)
• 変数定義(Variable Definition)
値に名前を与える。ある値が何度も出現するときなどに有用
一般形: (define 変数名 値)
例:円周率 π を3.14とする (define PI 3.14)
PIの参照を3.14 で置き換える: DrRacket の実行例
> (define PI 3.14)
> PI
3.14
プログラムとその構成要素:関数定義
計算等の実行手順 (前述のような式や定義から
構成)にも名前をつけることができる:関数定義
Scheme の関数定義の例
半径rの円の面積を求める
関数area-of-diskを定義
(define (area-of-disk r)
(* PI (* r r)))
area-of-disk (r) = PI * r 2
円の面積を求める関数の定義例:
• 半径 r の値から円の面積 (* PI (*
r r)) を計算
する手順に area-of-disk という名前をつけている
円の面積
r (円の面積)
半径 r の円の面積は π r2
円の面積を求める関数の定義
(define (area-of-disk r)
(* PI (* r r)))
この部分は Scheme の式
(実行時に指定される半径は
変数 r として表現)
円の面積を求める関数の定義
(define (area-of-disk r)
(* PI (* r r)))
実行時に値を1つ(名前はr)受取る
関数の引数(パラメータ)という
内部の式ではrの値から(* PI (* r r))を計算
関数を使ったプログラム
• プログラム中における関数の実行(関数適用)
– 入力(与えるデータ)と出力(受け取る結果)がある
– 定義名(手順に付けられた名前)と必要な入力デー
タを与えて計算を呼び出す。 area-of-disk (r) = PI * r 2
入力
r の値: 5
(area-of-disk 5)
area-of-disk の定
義本体部分を呼び出す
(このとき r は5で置換)
(* PI (* 5 5))
= (* 3.14 25)
= 78.5
出力
78.5
まとめ
• 関数 = プログラムの構成単位
「関数定義である」ことを
示すキーワード
関数の名前
(define (area-of-disk r)
(* PI (* r r)))
r の値から(* PI (* r r))
を計算(出力)
関数
定義
引数として値を1つ
受け取る(入力)
C言語での例
//(define PI 3.14)
//(define (area-of-disk r) (* PI (* r r)))
#include <stdio.h>
#include <math.h>
double area_of_disk(double r){
return (M_PI * r * r); // M_PIはmath.hの中で定義
}
int main(){
double r=5.0;
printf(“%f”,area_of_disk(r) );
return(0);
}
練習2.
以下で、計算の精度を上げるためにPIの
小数点以下を一桁増やすにはどうしたらよ
いか。また r が5の時の結果はどうなるか。
(define PI 3.14)
(define (area-of-disk r)
(* PI (* r r)))
練習2. 解答
以下で、計算の精度を上げるためにPIの
小数点以下を一桁増やすにはどうしたらよ
いか。 (define PI 3.141)
(define (area-of-disk r)
(* PI (* r r)))
また r が5の時の結果はどうなるか。
>(area-of-disk 5)
(* PI (* 5 5))
(* 3.141 25)
78.525
練習3:関数定義
二数の和を求める関数 wa と積を求める
関数 seki を作成し,実行例を示せ
解答例:
(define (wa x y) (+ x y))
実行例:
> (wa 10 20)
30
練習3:関数定義(解答)
二数の和を求める関数 wa と積を求める
関数 seki を作成し,実行例を示せ
解答例:
(define (wa x y)
(+ x y))
(define (seki x y) (* x y))
実行例:
> (wa 10 20)
30
> (seki 10 20)
200
間違いの例:構文エラー
• 「スペース(空白文字)」に意味がある
• 括弧に注意
間違いの例 1
間違いの例 2
(* (+2 2)
(* (+ 2 2)
(/ (* (+ 3 5)
(/ (* (+ 3 5)
(/ 30 10))
(/ 30 10))
2))
2) )
+の後にスペースが無い
括弧の不足
種々のエラー
• 構文エラー(Syntax Errors)
処理系が見つける
(DrRacket)
• 言語Schemeの文法に合っていない場合
e.g. (10) (10 + 20)
• 実行時エラー(Run-time Errors)
• Schemeの文法に合っているが,結果を返さな
い場合.
e.g. (/ 1 0) (define (f n) (+ (/ n 3) 2)) に対する (f 5 8)
• 論理的エラー(Logical Errors)
• Schemeの文法に合っていて,結果も返すが,その結果が
間違っている場合(多くの場合は原因の特定が困難)
e.g. (define (area-of-triangle b h) (+ b h))
注意深く論理的に正しく
プログラムを設計するこ
とで回避 → 設計レシピ
(define (wage h) (+ 12 h))
問題
• 次は、何エラーというか?
• (10 + 20)
• (define (P x) (+ (x) 10))
に対する(P 5)
• (define (f n) (+ (/ n 3) 2))
に対する(f 10 20)
;; area-of-ring:半径rの円の面積を求める
• (define (area-of-ring r)
(* 2 PI r))
今日の練習問題
課題1. ドルから円への変換
•
ドル d から円を求める関数 d2y を作成
し,実行例を示すこと
– 関数の定義には define を使う
–
1ドルは,120.70円とする
(2014/12/09 現在)
(define Yen/Dollar 120.70)
;;d2y: number -> number
;;(d2y 1) should return 120.70
(define (d2y dollar)
(* dollar Yen/Dollar))
(d2y 1)
#include <stdio.h>
double YenDollar=120.70;
double d2y(double d){
return (d * YenDollar);
}
int main(){
double d=1.0;
printf(“%f”,d2y(d));
return (0);
}
課題のヒント(解答例)
• x から「10 × x + 30」 を求める関数 foo
を作成し,実行結果を報告しなさい
解答の例:
(define (foo x)
(+ (* 10 x) 30))
実行結果は次の通りと期待される
(foo 10) は 130
(foo 20) は 230
(あくまでも例です.各自、工夫を試みてください.
独自の工夫を高く評価します)
課題のヒント
• ここにあるのは「間違い」の例です.同じ間違い
をしないこと
1. 「かっこ」の間違い
define (d2y d)
(* 120.53 d)
⇒ 全体をかっこで囲むこと
2. 変数名の対応の間違い
(define (d2y dollar)
(* 120.53 d))
⇒ 変数名dとdollarはどちら
かに統一すること(どちらでも可)
3. 関数の書き方の間違い
(define (d2y)
(* 120.53 d))
⇒ d2y の後に d が必要
4. 関数名の付け方の間違い
(define (d 2 y d)
(* 120.53 d))
⇒ 「d 2 y」でなく 「d2y」
と書くこと
課題2. 摂氏から華氏への変換
•
摂氏(Celsius)表現の温度 c から華氏
(Fahrenheit)表現の温度 f を求める関
数 c2f を作成し,実行例を示しなさい
–
関数定義には define を使う
–
摂氏と華氏の変換式: c=5 ×(f - 32) / 9
;;c2f : number -> number
;; f = 9/5 * c + 32
;;(c2f 5) should return 41
(define (c2f c)
(+ (* (/ 9 5) c) 32))
課題3.
元利の計算
(define (interest base rate year)
•
(* base (expt (+ 1 rate) year)))
元金と年利と年数を受け取り、元利を求める
関数 interest を作成し,実行例を示せ
–
関数定義には define を使う
–
元利の計算式:
「元利 = 元金 × (1+年利)年数」
–
作成した関数を実行し,元金1000円,年利2%で
の,50年後の元利を報告しなさい
–
x の y 乗の計算には exptを使う:(expt x y)
2691.5880290736053938940873551... の値が返る