Lecture on Programming I 5/17

Menu Menu


先週の復習

    typing の練習
    様々なループ
    サブルーチン
    配列


Typing の練習

今日も typing の練習をすること (20分)

結果をscript でメールすること。

整形した結果を、

    Subject: Report on Programming I   5/17-typist

というサブジェクトで、kono@ie.u-ryukyu.ac.jp までメールを出すこと。

    % rsh pw006 "Mail -s 'Report on Programming I   5/17-typist' kono@ie.u-ryuky

u.ac.jp" < typescript


レポートについて

Indentation は、必ず守ること

ソースに関する説明を付けること


マニュアルの読み方

perldata を読もう。


変数と配列

変数は、値が一つ。スカラ (scalar) と呼ばれる。

配列は、値が複数。アレイ (array) と呼ばれる。

更に、添え字が文字などだと連想配列となる。これはハッシュ (hash)と呼ばれる。


(おまけ) 何故、ハッシュと呼ばれるのか?

連想配列は、
	文字列=>ランダムな数値

を、決まった値で生成するハッシュ関数を使って実現されているから。

    $hash{'test'} 

は、

    $hash[ &hash('test') ]

とのような感じで配列として実現されている。(実際には、もう少し下位の実装で実現されている)hash 関数は Perl の内部で実装されている。


Perl の構文について

エラーの読み方

正しい文の作り方

式とは何か?

文とは何か?

文法構造とはなにか?

    if-statement 
	: if ( condition ) { statement }
	| if ( condition ) { statement } else { statement }
	| if ( condition ) { statement } else-if-statement
	;
    else-if-statement
	: elsif ( condition ) { statement }
	| elsif ( condition ) { statement } else { statement }
	| elsif ( condition ) else-if-statement
	;

このことについてはコンパイラの授業で詳しく習う。


Perlの参照

変数の値と名前を区別しよう。

    $a というのは、値を入れる箱
    箱に中に入っているのが値

代入とは、箱の中の値を書き換えること。

    $a = 3;


Turtle (亀) の作り方

    $x = 0; $y = 0;

とすると、亀の位置を二次元で表すことができる。二次元上で、亀を動かすことを考えよう。

亀の方向を $direction に角度を単位で格納する。

    $direction = 0;

方向を変えると、$x, $y 方向に進む量が変わる。sin/cos を思いだそう。

    $sin = sin($direction / 360 * 3.1415926 );    
    $cos = cos($direction / 360 * 3.1415926 );    

前に進むには、

    $x += $cos;
    $y += $sin;

とすれば良い。


問題

向きを変えるサブルーチン direction と、前に進むサブルーチン forward そして、今の位置を表示するサブルーチン print を作れ。


subroutine の結果の返し方

最後に使った値、または、return で指定した値が返される。

@_ には、参照が入っている。


問題

亀を複数作るには、どうすれば良い?

    変数名を増やす
    配列を使う

これを、ちゃんと解決するには、参照という技術を使ってオブジェクトを作るのが良い。


オブジェクトを使った解決

複数の亀をきれいに扱うには、

    亀を表すデータの集合
    亀を動かすサブルーチンの集合

を結びつければ良い。

Perl では、

    亀を表すデータの集合を、連想配列を使った参照で表す
    亀を動かすサブルーチンの集合を Package で作る
    その二つを結びつける bless というのを用意する

という手法で、オブジェクトを実現している。

まず、最初に、参照 (Reference )について勉強しよう。


Reference in Perl

Perlのデータは、配列と[1,2,3]と連想配列{'a',1,'b',2} を使うことができる。
これらは、リスト(1,2,3)と違って無名配列(Anonymous Array) 、無名連想配列(Anonymous Hash)と呼ばれる。これらは名前がないので、直接$a{'test'}などというようには扱えない。実際には、これらは配列への参照であり、以下のように使う。

    pw071: {1} % perl5 -de 0
    Loading DB routines from perl5db.pl version 1
    Emacs support available.
    Enter h or `h h' for help.
    main::(-e:1):   0
      DB<1> @a = (1,2,3,4,5)
      DB<2> p "@a"
    1 2 3 4 5
      DB<3> @b = @a
      DB<4> p "@b"
    1 2 3 4 5
      DB<5> $a[2]="kono"
      DB<6> p "@a"
    1 2 kono 4 5
      DB<7> p "@b"
    1 2 3 4 5
      DB<8> $a = [1,2,3,4,5]
      DB<9> p $a
    ARRAY(0x805b3b4)
      DB<10> p @$a
    12345
      DB<11> p "@$a"
    1 2 3 4 5
      DB<12> $$a[1] = "kono"
      DB<13> p "@$a"
    1 kono 3 4 5
      DB<14> $b = $a
      DB<15> $$b[2] = "kakazu"
      DB<16> p "@$b"
    1 kono kakazu 4 5
      DB<17> p $b
    ARRAY(0x805b3b4)
      DB<18> p $b->[2] = "higa"
    higa
      DB<19> p "@$b"
    1 kono higa 4 5
      DB<20> $c = {}
      DB<21> $c->{'kono'} = 'teacher'
      DB<22> $c->{'higa'} = 'student'
      DB<23> p %$c
    higastudentkonoteacher
      DB<24> $c{'kono'} = 1
      DB<25> $c{'higa'} = 2
      DB<26> p keys %c
    higakono
      DB<27> p $c
    HASH(0x8134cc0)

プログラムの中に現れるPerlのデータは、\ を付けることによって参照を取ることができる。

  DB<28> $d  = \%c
  DB<29> p $d
    HASH(0x8152b00)
  DB<30> $d->{'shimabukuro'} = 'student'
  DB<31> p keys %c
    higashimabukurokono
  DB<32> 


問題

以下の例題を動かしてみて、Perlの参照の振る舞いを理解すること。出力を確認し、結果を提出する事。

     $a=[1,2,3,4];
     $a->[5]=3;
     print "@$a, $a->[2]\n";
     $b={};
     $b->{First}='Cat';
     $b->{Second}='Dog';
     $b->{Third}='Pig';
     foreach $key ( keys %$b)  { print "$key is $b->{$key}\n"  }

     @a =  ( 1,2,3,4);
     $refa = \@a;
     $refa->[5]=3;
     print "@$refa, $refa->[2]\n";


問題

連想配列を使って、亀を複数作ることを考える。

    $kame{'-x'}
    $kame{'-y'}
    $kame{'-direction'}
    $kame{'-sin'}
    $kame{'-cos'}

この連想配列を二つ作り、参照を使ってサブルーチンに渡す。

    $kame1{'-x'}
    $kame1{'-y'}
    $kame1{'-direction'}
    $kame1{'-sin'}
    $kame1{'-cos'}
    $kame = \%kame;
    $kame1 = \%kame1;

この参照を操作する、direction, forward, print を作れ。

解答例 一旦、連想配列を作る方法は、少し無駄である。初期化ルーチンを別に作るのが望ましい。

しかし、この方法では、これらを操作するサブルーチンと、データ構造 (オブジェクトの内部状態) の表現が別々になっている。

その接続を考える前に、Package というサブルーチンの集合を勉強しよう。


Package / Module

大規模なプログラムでは、変数や手続き名の数は数百以上になる。良く使われる語彙は500程度と言われているので、必然的に同じ名前を使うか、無意味な識別名を使う必要に迫られる。一方で、iとかjとかは一時変数として便利なので、良く使うことが多い。

そこで名前空間というのを考える。名前空間が異なる場合は、そこでは同じ同じ字面でも異なる名前をさすことになる。名前空間は、パッケージ(Package)または、モジュール(Module)と呼ばれる。C では、static というキーワードによりファイルに局所的な名前を作成することができる。これにより疑似的な名前空間を作ることができる。

Perl のpackage は、package Hogehoe; と記述することによって作られる。

package 形式になったファイルは、hogehoge.pm という(Perl Module)拡張子をつける。これにより、use hogehoge; という形で Module を使用することができる。(通常のファイルは do "filename.pl"; というのを使う) ( perlmod を参照すること)


Object in Perl

これで、ようやく、Perl でオブジェクトを作る準備ができた。

Perlのオブジェクトは、Package と無名データを結び付けることによって作られる。( perlobj Perl のオブジェクト を参照すること、さらに、 perlbot Bag'o Object Tricks For Perl5 (the BOT) も見る方が良い。)

無名データをオブジェクトの持つ内部構造として、これにオブジェクトの操作方法を記述した Package を対応させると Perl のオブジェクトができあがる。この二つを結び付けるのが bless という演算子だある。

出来上がりのPackage の例
それを動かすテストプログラム。

前の 解答例 と比較してみよう。


Turtle Graphics

Turtle Graphics とは? Turtle とは、亀のこと。亀を動かすことにより、絵を書いていくもの。実際に、Perl/Tk で、絵を書くことができるものがあるので、それを使ってみよう。

    #!/usr/local/bin/perl5
    use Turtle;                # Turtle モジュールを使う
    $turtle = Turtle->create();    # 亀を作る
    $turtle->color('red');         # 色の設定
    $turtle->width(3);             # 大きさの設定
    $turtle->color('none');        # 色無し
    $turtle->move(100,100);        # 100,100 に移動する
    $turtle->color('black');       # 色を黒くして
    $turtle->move(10,00);          # 右に10移動
    $turtle->move(00,10);          # 下に10移動
    $turtle->color('green');       # 色を緑に
    $turtle->move(-10,00);         # 左に10移動
    $turtle->move(00,-10);         # 下に10移動
    $turtle->MainLoop();           # quit が押されるまで待つ

まず、モジュールをコピーしよう。

    rcp pw006:/usr/open/classes/kono/programming1/Turtle/\* .

または、/usr/open があるpw ならば、
    cp /usr/open/classes/kono/programming1/Turtle/* .

または、 ここ です。

注! パッケージである これ 単独では動きません。これを動かす テストプログラム から動かそう。


Perl のオブジェクト

    $turtle = Turtle->create();

は、Turtle というオブジェクト(Object = もの)を作っています。

    $turtle->color('red');

などは、オブジェクトに対する操作で、メソッド呼出し、または、メッセージ送信と呼ばれるものです。


Turtle.pm

Turtle.pm は、Perl/Tk を使って書かれている。

Turtle.pm で使われている Perl/Tk の機能をマニュアルで確認せよ。

Canvas を調べると良い。

(3) name() と erase() のメソッドの役割を想像し、実際に動作させてみよ。


渦巻き

以下のような渦巻型を引数で指定された大きさで、表示するプログラムを作成せよ。

引数は、

	$count = $ARGV[0]

という形でとることができる。


渦巻型のプログラムの作り方の例

まず、渦巻の最初の座標を手で計算してみる。この時に、紙ではなく、エディタを使うとそれをそのままプログラムのコメントに使用できる。

       +----20+10-------+
       |
      20 
       |     ---10-+
       |           |
       |          10
       +----20-----+

これを書くための Turtle の動きを考えよう。
           
 forward 10             
 right                 
 forward 10           
 right               
 forward 20
 right 
 forward 20
  .....

毎回、右に曲がるのは良いとして、同じ距離だけ2回動いて、10 だけ進む距離を増やすのが良いらしい。(ちょっと考えれば理由はすぐにわかる)

これを、for 文で書いてみよう。

    $length = 10;
    for($i=0;$i<$count;$i++) {
	&forward($length);
	&right();
	&forward($length);
	&right();
	$length += 10;
    }

こんな感じか? ここで $count は、進む数。ただし、二つずつになっている。
	$i++              $i を一つ増やす
	$length += 10     $length を 10増やす

という慣用句に注意しよう。

Turtle.pm には、(まだ) forward と right がないので自分で作る。いきなり、Turtle を呼ばないで、座標を計算して表示させるものを作ろう。

    sub forward {
	my ($length) = @_;
	if ($dir == 0) {
	    $x += $length;
	    print "forwad $legnth (X = $x,Y = $y)\n";
	} elsif ($dir==90) {
	    $y += $length;
	    print "forwad $legnth (X = $x,Y = $y)\n";
         ...
	}
    }

方向を曲げるのは簡単で、
    sub right {
	$dir += 90;
	$dir %= 360;
    }

とすれば、良い。%= は、割算の余りを計算している。(本当は、これらのものは、Turtle graphics のlibraryのなかに入っているべきだ)

これを動かして、座標を確認する。正しい座標が表示されなかったら、プログラムを見直そう。

正しく動いたら、Turtle graphics に関するさまざまなものや、$count を引数から受け取る部分を記述する。

さっき書いた絵も、コメントとしていれておくのが良い。このようにして、作られたのが、 です。


Turtle Graphics の問題

(1) サブルーチンを使って、四角を、20個四角く表示するプログラムを書け。

(2) sin,cos を使って、円を近似するプログラムを書け。

(3) 円を20個、四角く表示するプログラムを書け。

参考

test1.pl 四角を複数表示するプログラム

test2.pl 円を途中まで表示するプログラム


問題

二重の渦巻を書くプログラムを作成せよ。

四角い渦巻ではなく、丸い渦巻を作成するにはどうすれば良いか? 円をずらして実現する方法も考えられる。自己相似な渦巻も考えられる。


宿題

以上の課題を

  Subject: Report on Programming I   5/17

というサブジェクトで、kono@ie.u-ryukyu.ac.jp までメールを出すこと。


Shinji KONO / Sun May 20 01:04:38 2001