工学部2018年度 – プログラミング論I – 2018年度前期 (廣川) 工学部第15講義室(月曜1,2限目)
プログラミング論I 2年生前期:毎週月曜日1,2限目 目標:プログラムの基本設計法を習得 使用プログラミング言語:Scheme (後述)
なぜプログラミングを学習するか 問題分析、問題解決の技術 今やコンピュータは社会基盤の一部 コンピュータはデータを形式的(機械的)に処理 右下図:http://www.kkr.mlit.go.jp/river/keyword/images/03_01.jpgより 今やコンピュータは社会基盤の一部 コンピュータソフトウェアに関する素養は必須 コンピュータはデータを形式的(機械的)に処理 特定の言語によらず、データおよびその処理手順(プログラム)を論理的に記述する(というプログラミング)能力は重要 その際には テクニックよりまず基本的な考え方を重視 問題分析、問題解決の技術 プログラミングは,この訓練になる
プログラム設計法(レシピ) プログラム設計レシピ:問題解決過程のガイド 各ステップで中間生成物をチェック 問題の解析とデータの定義 規約、目的、結果の記述とヘッダ作成 例題を用いたプログラムの振舞の例示 プログラムテンプレート、レイアウトの作成 テンプレートを完全な定義に変換 テストを通してエラーの発見 各ステップで中間生成物をチェック (具体的な適用法や設計ごとのバリエーションは後述)
ソフトウェア開発と言語 Scheme という言語を使う ソフトウェア開発(抽象レベルでは言語非依存): 物理システムの開発と同様きちんとした抽象化、設計法 物理法則のような制約がない→論理的正しさが特に重要 具体的実現:目的に適した言語(モデル)を選択 モデル: 式、関数 / 手続き、副作用 / オブジェクト指向 等 目的:科学技術計算、事務処理、システムソフト、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://vega.cc.kyushu-u.ac.jp/~hirokawa/Programming/
Racket (Scheme処理系) http://download.racket-lang.org/ 自分のPCに合う物を 選択してください
DrRacketの起動画面 Language Choose Language
この画面にプログラムを書いて,RUNを押す プログラムの記述(1/2) (+ 1 2) (* 3 4) (/ 5 6) (- 7 8) この画面にプログラムを書いて,RUNを押す 3 12 0.83 -1 式の値が, 下の画面に現れる
プログラムの記述(2/2) ;; 1 dollar is 121.77 yen この画面にプログラムを書いたら,RUNを押す ;; 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 この画面にプログラムを書いたら,RUNを押す この画面にプログラムを書いたら,Enterを押す 関数定義の例 C言語での定義 の例 #include <stdio.h> double d2y(double d){ return (121.77*d); } int main(){ double d; printf(“d=“); scanf_s("%lf", &d); printf("%f\n", d2y(d)); return (0); Visual Studioの場合
1. Scheme の式とプログラム 数、式、プログラムと実行過程、エラー
本日の内容 Scheme プログラムとその処理系の概要 Scheme の簡単な式 Scheme の簡単な関数 プログラムの実行過程 エラー
Scheme プログラム データを処理(および入/出力)する手順の記述 データ: 処理: 単体(atomic)データ 複合(compound)データ 複数のデータで構成 (固定サイズ、任意サイズ) 処理: 基本(primitive)演算・関数 既存の関数を部品として使う関数 対象問題を解くため,これらを使った解決手順を書く: → プログラミング (本講義は基礎)
Scheme の実行イメージ 実行結果 計算手順をSchemeで記述 コンピュータ上のインタプリタ (解釈・実行ソフト) プログラムの呼出も可能 コンピュータ上の コンパイラ (翻訳ソフト) コンピュータ上のインタプリタ (解釈・実行ソフト) 計算が行われ,結果の表示 実行可能形式に変換 実行結果 コンピュータ上で実行 実行結果
Scheme の文法(基本レベル) 語彙 文法 変数 式 定数:数、記号、真偽値 5 -5 0.5 'a true など プログラミング言語も言語:語彙を文法に従って書き並べる 語彙 変数 定数:数、記号、真偽値 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 の式の例 -入れ子の式と括弧 - (* (+ 2 2) (/ (* (+ 3 5) (/ 30 10)) 2)) Scheme の式
括弧の意味 括弧が,計算の「単位」を表現している。 優先順位が高い単位から先に括弧で括る。 (* (+ 2 2) (/ (* (+ 3 5) (/ 30 10)) 2)) 括弧が,計算の「単位」を表現している。 優先順位が高い単位から先に括弧で括る。
計算過程 最初に最内のカッコで括られた式を数に簡約、 引き続き次の入れ子の層の計算を続ける (* (+ 2 2) (/ (* (+ 3 5) (/ 30 10)) 2)) = (* 4 (/ (* 8 3) 2)) = (* 4 (/ 24 2) ) = (* 4 12) = 48 左から右に,簡約が進む 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) >(* (+ 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 >(+ 5 5) 10 >(/ 8 12) 2/3 >(+ -5 5) >(+ 3 4.5) 7.5 >(* 3 4) 12
プログラムの構成要素:変数定義 ものには名前をつけることができる(定義) 通常、プログラムは数多くの定義からなる 関数定義:主関数、補助関数(後述) 変数定義(Variable Definition) 値に名前を与える。ある値が何度も出現するときなどに有用 一般形: (define 変数名 値) 例:円周率 π を3.14とする (define PI 3.14) PIの参照を3.14 で置き換える: DrRacket の実行例 > (define PI 3.14) > PI 3.14
プログラムとその構成要素:関数定義 計算等の実行手順 (前述のような式や定義から構成)にも名前をつけることができる:関数定義 半径rの円の面積を求める 関数area-of-diskを定義 Scheme の関数定義の例 (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
円の面積を求める関数の定義 この部分は Scheme の式 (実行時に指定される半径は 変数 r として表現) (define (area-of-disk r) (* PI (* r r))) この部分は Scheme の式 (実行時に指定される半径は 変数 r として表現)
円の面積を求める関数の定義 (define (area-of-disk r) (* PI (* r r))) 関数の引数(パラメータ)という 内部の式ではrの値から(* PI (* r r))を計算
area-of-disk (r) = PI * r 2 関数を使ったプログラム プログラム中における関数の実行(関数適用) 入力(与えるデータ)と出力(受け取る結果)がある 定義名(手順に付けられた名前)と必要な入力データを与えて計算を呼び出す。 area-of-disk (r) = PI * r 2 入力 出力 (area-of-disk 5) r の値: 5 78.5 area-of-disk の定義本体部分を呼び出す(このとき r は5で置換) (* PI (* 5 5)) = (* 3.14 25) = 78.5
まとめ 関数 = プログラムの構成単位 (define (area-of-disk r) (* PI (* r r))) 関数 定義 「関数定義である」ことを 示すキーワード 関数の名前 (define (area-of-disk r) (* PI (* r r))) 関数 定義 引数として値を1つ 受け取る(入力) r の値から(* PI (* r r)) を計算(出力)
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の 小数点以下を一桁増やすにはどうしたらよ いか。 練習2. 解答 以下で、計算の精度を上げるためにPIの 小数点以下を一桁増やすにはどうしたらよ いか。 また r が5の時の結果はどうなるか。 (define PI 3.141) (define (area-of-disk r) (* PI (* r r))) >(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
間違いの例:構文エラー 「スペース(空白文字)」に意味がある 括弧に注意 (* (+2 2) (* (+ 2 2) 間違いの例 1 間違いの例 2 (* (+2 2) (/ (* (+ 3 5) (/ 30 10)) 2)) (* (+ 2 2) (/ (* (+ 3 5) (/ 30 10)) 2) ) +の後にスペースが無い 括弧の不足
種々のエラー 構文エラー(Syntax Errors) 実行時エラー(Run-time Errors) 処理系が見つける (DrRacket) 構文エラー(Syntax Errors) 言語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)) (f 5 8)は,定義された引数の数と異なる数の引数が与えられている. 注意深く論理的に正しくプログラムを設計することで回避 → 設計レシピ
問題 次は、何エラーというか? (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 現在) #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); (define Yen/Dollar 120.70) ;;d2y: number -> number ;;(d2y 1) should return 120.70 (define (d2y dollar) (* dollar Yen/Dollar)) (d2y 1)
課題のヒント(解答例) x から「10 × x + 30」 を求める関数 fooを作成し,実行結果を報告しなさい 解答の例: 解答の例: (define (foo x) (+ (* 10 x) 30)) 実行結果は次の通りと期待される (foo 10) は 130 (foo 20) は 230 (あくまでも例です.各自、工夫を試みてください. 独自の工夫を高く評価します)
課題のヒント ここにあるのは「間違い」の例です.同じ間違いをしないこと 1. 「かっこ」の間違い 3. 関数の書き方の間違い define (d2y d) (* 120.53 d) (define (d2y) (* 120.53 d)) ⇒ 全体をかっこで囲むこと ⇒ d2y の後に d が必要 2. 変数名の対応の間違い 4. 関数名の付け方の間違い (define (d2y dollar) (* 120.53 d)) (define (d 2 y d) (* 120.53 d)) ⇒ 変数名dとdollarはどちらかに統一すること(どちらでも可) ⇒ 「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) (define (interest base rate year) (* base (expt (+ 1 rate) year))) 2691.5880290736053938940873551... の値が返る