class: title, smokescreen, shelf, no-footer # 関数とは何か? <div class=footnote> <small> Copyright 2022 (C) Ken'ichi Fukamachi (<A HREF=https://www.fml.org/>fml.org</A>), CC BY-NC-SA </small> </div class=footnote> --- class: compact # 関数のふんわりした話 <div class=footnote> <small> (脚注) Perlの関数宣言はsubというキーワードを使います。 関数(function)とサブルーチン(subroutine)という用語があって、 本来は微妙に違うらしいのですが、 現代では実用上おなじだとおもっていいのではないかと思われ </small> </div class=footnote> - (長い)プログラムは、小さな部分に分けて、それらを組み上げて作ります - そうすると読みやすく=理解しやすくなります - 複数人で分担して作業(作成)できるようになります - だいたいのプログラムは「入力」「計算する(プログラムの実体)」「出力」です - これまでは一つの長いプログラムを書いていたので、 **入力=「ユーザがキーボードから文字や数字を入れる」こと**、 **出力=「モニタへ文字や数字が出てくる」**でした ``` // プログラム(全体) (キーボードから)入力 -> (一つの大きな)プログラム -> (モニタへの)出力 // プログラムの中で; 「渡す/返す」と「入力/出力」なじめる表現でok(問題文は前者の表現なので慣れてね) (プログラムのmain)から渡す -> 関数 -> (main)へ返す (プログラムのmain)から入力 -> 関数 -> (main)への出力 ``` --- class: compact # 関数のふんわりした話 ``` // プログラム(全体) (キーボードから)入力 -> プログラム -> (モニタへの)出力 // 関数(プログラムの一部の動作); 「渡す/返す」と「入力/出力」なじめる表現でok(問題文は前者の表現なので慣れてね) mainから渡す -> 関数 -> mainへ返す mainから入力 -> 関数 -> mainへの出力 mainから発注 -> 関数 -> mainへ納品 mainから発注 -> 下請 -> mainへ納品 ``` - (長い)プログラムは「mainから**下請け(関数**)に仕事を依頼する」作業の連続です - 仕事を依頼する際にコピーを渡しています - 納品もコピーをもらいます ![height120px](../../clang/function/images/document_hacchusyo.png) ![height120px](../../clang/function/images/copy_woman.png) ![height120px](../../clang/function/images/business_shitauke.png) ![height120px](../../clang/function/images/business_shitauke_2ji.png) ![height120px](../../clang/function/images/business_shitauke_3ji.png) ![height120px](../../clang/function/images/copy_man.png) ![height120px](../../clang/function/images/document_nouhinsyo.png) --- class: img-right,compact # プログラムたとえ話「学食」 <div class=footnote> <small> </small> </div> ![height400px](../../clang/function/images/P_20191001_133127.jpg) (1つのプログラム「昼ご飯」全体) 1. 食券を買う (次頁) 1. 食券を渡す 1. 該当する食事をもらう 1. 食べる 1. 食器を返す --- class: img-right,compact # 関数たとえ話「食券を買う」 <div class=footnote> <small> (脚注1) 裏側で何をやってるかはブラックボックスになります。 この隠蔽という性質も関数の特徴です <br> (脚注2) 食券(関数)が、 さらに小さな関数「印刷」「紙を切る」「チケットを落とす」を呼び出すでしょう </small> </div> ![height400px](../../clang/function/images/P_20191001_133127.jpg) - だいたいのプログラムは「入力」「計算する(プログラムの実体)」「出力」 - 学食のチケット販売機(右図,昔の学食)も同じでしょ? 1. お金を入れる(入力) 1. メニューボタンが押される 1. (裏側で)なにか計算(仕事)している - たぶん裏で -> 印刷 -> 切る -> チケットを下へ落とす 1. チケットとおつりが出てくる(出力) --- class: col-2,compact # 擬似コード「食券を買う」 <div class=footnote> <small> いったん、公式へ飛びましょう </small> </div> 簡単化のため、メニューが一つしかない(メニュー番号の指定がない)場合、 食券を買う動作は次のようになるでしょう 1. おかねをいれる 1. (裏側で印刷したり準備) 1. チケットが出てくる ``` // 擬似コードで書くと、こんな感じでしょうか // おかね(IN) -> 販売機 -> チケット(OUT) sub 食券を買う (おかね) { # 裏側で行われる食券販売機の実体を書く return チケット; } sub shokken_kau { my ($okane) = @_; # 裏側で行われる食券販売機の実体を書く return $ticket; } ``` --- class: title, smokescreen, shelf, no-footer # じゃんけんを関数化しよう <div class=footnote> <small> </small> </div> --- class: compact # 前回までのおさらい: じゃんけんの模範解答 <div class=footnote> <small> (脚注)<A HREF="examples/janken_loop.pl.txt">examples/janken_loop.pl.txt</A> ... でも、これ3とかも入力できますけど...? </small> </div> ``` JANKEN: # ループのラベル while (my $jibun = <>) { # キーボードからの入力 chomp $jibun; # 不要な改行コード(ENTER分)を削除 # 命令が先、条件がつづくスタイル; JANKENループを終了 last JANKEN if $jibun eq "q" || $jibun == 9; # コンピュータの手は乱数で0 or 1 or 2を生成 my $aite = int(rand(3)); # 結果: 0 = あいこ, 1 = 負け, 2 = 勝ち my $kekka = (3 + $jibun - $aite) % 3; if ($kekka == 0) { print "aiko\n";} elsif ($kekka == 1) { print "make\n";} elsif ($kekka == 2) { print "kachi\n";} } ``` --- class: compact # 課題: じゃんけんを関数化しよう <div class=footnote> <small> </small> </div> 流れを考えると、こうですよね? 1. キーボードから(ユーザ=jibun)の手を入力 1. コンピュータの手を乱数で決める 1. じゃんけんの判定を計算 1. 出力 ![height120px](../../clang/function/images/document_hacchusyo.png) ![height120px](../../clang/function/images/copy_woman.png) ![height120px](../../clang/function/images/business_shitauke.png) ![height120px](../../clang/function/images/business_shitauke_2ji.png) ![height120px](../../clang/function/images/business_shitauke_3ji.png) ![height120px](../../clang/function/images/copy_man.png) ![height120px](../../clang/function/images/document_nouhinsyo.png) --- class: compact # 課題(例題): コンピュータの手を関数化 コンピュータの手を決めるところは、ここのところですね? ``` # コンピュータの手は乱数で0 or 1 or 2を生成 my $aite = int(rand(3)); ``` ここを関数に置き換えてください ![height120px](../../clang/function/images/document_hacchusyo.png) ![height120px](../../clang/function/images/copy_woman.png) ![height120px](../../clang/function/images/business_shitauke.png) ![height120px](../../clang/function/images/business_shitauke_2ji.png) ![height120px](../../clang/function/images/business_shitauke_3ji.png) ![height120px](../../clang/function/images/copy_man.png) ![height120px](../../clang/function/images/document_nouhinsyo.png) --- class: compact # 考え方: コンピュータの手を関数化(1) <div class=footnote> <small> </small> </div> ``` # コンピュータの手は乱数で0 or 1 or 2を生成 my $aite = int(rand(3)); ``` は ``` # コンピュータの手は乱数で0 or 1 or 2を生成 my $aite = janken_aite(); ``` と書き換えるのが妥当でしょう。ここで考えてたことは次のとおり - `janken_aite()`に依頼したい(発注書に書く)情報はあるかな? -> ない -> `()`と書いた - `janken_aite()`から返してほしい情報は何? -> 数字の 0 or 1 or 2 - `$aite`に代入するのは一緒なので`=`の右側を書き換えるだけ --- class: compact # 課題(解答): コンピュータの手を関数化(2) では関数本体を書きましょう。 関数本体の元ネタは、これ。 あ、代入は不要だよね ``` # コンピュータの手は乱数で0 or 1 or 2を生成 my $aite = int(rand(3)); ``` このコードで意味のある実(本体)は、ここ(0 or 1 or 2 の生成部分)だけ ``` int(rand(3)); ``` あとは、このまわりに関数呼び出しの呪文を書けばいいのね ``` sub janken_aite { # sub 関数名 { ...関数本体... } int(rand(3)); } ``` 終わりです --- class: compact # 課題(解答): コンピュータの手を関数化(3) 注意点として、Perlでは最後に return を書かなくても最後の文の値が返されますが、 意図がわかりやすいように return を書くのはよいこころがけです。 return が必須の言語もあるし、どういうスキルの人が読むか分からないから、 「つねに他人が読んで誤解しないコードを心がける」ことは重要です。 ``` sub janken_aite { # sub 関数名 { ...関数本体... } return int(rand(3)); } ``` --- class: compact # 課題 <div class=footnote> <small> 各課題、まず渡したい情報と返したい情報を考えてください <br> 課題「もぐらたたきの関数化」は正規表現をやってからね </small> </div> 1. 判定を関数化してください 1. 出力を関数化してください 1. 入力を関数化してください [ワークシート](../worksheet/sub.pdf) --- class: title, smokescreen, shelf, no-footer # もぐらたたきを関数化しよう <div class=footnote> <small> このへんまできたら、ノーヒントで行けますかね? </small> </div> --- class: compact # もぐらたたきの関数化 <div class=footnote> <small> 発展課題をやるのもよいでしょう。 発展課題になればなるほど長いプログラムになるので、 関数化を心がけたほうが読みやすいとは思います。 でも関数化という別の練習になっちゃうからね、 どっちを優先するか?は各自の判断でよいかと思います </small> </div> (だいぶヤマ勘で書いてますけど) 1. もぐらの初期位置決めをする関数 1. 入力をする関数 - 1回呼ぶバージョンと2回呼ぶバージョンがありうるよね 1. もぐらがいたか否かを判定する関数 1. 出力する関数 - 9x9の升目を表示する部分は、きっとここ。描画関数くらいの勢いですな