05. SNAP!でオブジェクト指向(4/4)

Q&A SNAP!でペンの色をRGBで指定したい。 https://twitter.com/_kobashi/status/991320930394685441

前回の補足:

WebのHTMLファイル中の単語の数え上げ。

・文字データの単語化

・単語の辞書登録と登場回数のカウント

・辞書の単語を登場回数順に並べ替え

について解説。

関数スタイルのプログラミング:

関数オブジェクトによるリスト処理を中心としたプログラミングスタイル。

Viscuitで表現した場合:

関数型プログラミングに登場するデータ処理

map と filter と stream をviscuit で表現 http://develop.viscuit.com/3.1/Land.html?path=2518958&name=83&smoothMotion=true&dynamicFile=false

ループ処理が明示的に現れないプログラミングスタイル

※ stream については、本講義のJavaのプログラムで扱う予定。特徴:遅延評価 無限データ構造

ポイント:

リスト処理 リスト作成 要素の追加と削除 階層構造

map 関数 リストの個々の要素すべてを別の要素に置き換えた新しいリストを作成するデータ変換処理

assoc 関数 辞書登録 と 辞書検索

for each リストの全要素に対する繰り返し処理。map関数のブロック版。

高階関数(higher order function) 関数を処理する関数。ブロックを引数に指定して使うブロック。

例) sort

■ 言語機能の拡張(その1)

以下の説明を、このページのファイル SNAP4_4_a.xmlダウンロードして、インポートしてから進める。

SNAP!の起動。

プログラムの 継続 について復習。

コマンドブロックの引数と、引数を指定して実行について確認。

コマンド引数の 可変長引数リスト について確認。

引数を省略した際の自動割り当てについて確認。

継続を利用した switch case ブロックの作成例)

以下で、引数の型に応じて処理を変更する例を示す。

※引数の値ではなく、型をチェックするブロックを もし ブロックで利用していることに注目する

※このように、データの型に応じて振る舞いを変えるというプログラムの考え方は、今回の後半の オブジェクト指向 でも重要である。

switch case の拡張版、 matchの作成例)

条件判定で、変数の値の他に、関数を利用できるように switch を修正する。

高階関数的な match ブロックを作成する。

match では、 case ブロックで 値の他に 引数が一つの判定式(判定結果が bool値 となる述語) を使うことが出来る。

※上の画像には、リング化ブロック(関数オブジェクト)の引数を省略した場合の特殊な動作の例が示されている。

※ 〇 を 3 で割った余り のブロックで 〇が未指定になっている。この場合、リングの第1引数として 〇 が扱われる。

match と if ブロックの比較

■ 言語機能の拡張(その2)

プロトタイプベースのオブジェクト指向機構をSNAP!に実装する。

目的: オブジェクト指向言語の文法だけでなく、コードの動作原理を理解することで、より深くオブジェクト指向を理解する。

オブジェクト指向言語のコードは魔術的:

コードを読んだだけでは、内部の動作が表現されいないので、動作原理が分からない。

魔法の呪文を覚えるだけ(コードの文法を覚えるだけ)ではなく、その動作原理を理解することで、より深く魔法(オブジェクト指向)を理解する。

状態を持つオブジェクトを生成するコード:

大域変数以外の変数は、プログラムの実行終了時に失われる(再利用できない)

SNAP!では、その例外として、スプライト変数を利用することができた。

これは、スプライトのxy座標や画像と同様、各スプライトオブジェクト事に固有の独立した変数である。

オブジェクトを生成するプログラムの作成を試みる。

スプライトには

振る舞い(メソッド): 歩く 回る 音を出す

プロパティ: 座標 サイズ 向き 画像 音声

のようなオブジェクトが所有する、コード(メソッド)とデータがある。

オブジェクトの生成では、これ同様にオブジェクトに所属するコードとデータをオブジェクトに持たせることになる。

カウンターオブジェクトを作成して、動作を確認する。

P.57 A. Local State with Script Variables

練習:モニター(値を生成するブロック。コマンドエディターのブロックのタイプを選択する際に選択)ブロックとして make a counter ブロックを作成する。

ブロックの名前は make a counter

状態を持つオブジェクトを生成するブロック make a counter の定義:

動作確認:

変数 a と 変数 b でカウンターの値が独立して保存されていることがわかる。

※ make a counter でリング化ブロック(関数オブジェクト)を利用して、スクリプト変数(通常はプログラム実行後に消滅)をリング化ブロック内に閉じ込めることができる。リング化ブロック自体は、make a counterの実行結果の値(オブジェクト)としてグローバル変数に保存する。

オブジェクトが存在している間は閉じ込められた変数も存在することになる。

このような関数オブジェクトを クロージャ と呼ぶ。

※ クロージャ内部で利用された外部の変数は、クロージャ内に閉じ込められる。

課題提出: counter オブジェクトの生成と実行を確認してスクリーンショットにとる。Webclassにアップロード。

P.58 B. Messages and Dispatch Procedures

プログラムをメッセージで制御するプログラムの作成

askブロック作成上の注意点:

・ブロック引数の型

1つ目 コマンド(インライン) を指定

2つ目 通常の全タイプ

3つ目 複数の引数

・非リング化

callブロック(・・・を呼ぶ ブロック)は、引数に他のブロックをセットすると自動的にリング化してしまう。

今回利用するブロックは、リング化されたプログラムを返すモニター(関数)なので、二重にリング化されてしまい、そのままでは不都合。

自動的にリング化された部分を、右クリックして 非リング化 する。

・引数で呼ぶ と 引数リストで呼ぶ の違い

外側の 呼ぶブロック を引数リストで呼ぶように修正。第3パラメータのブロックを 呼ぶブロック の▲部分にドラッグ&ドロップするとブロックのタイプが変更される。

このページまでの作業結果を保存したファイルを、このページに添付しておくので、ダウンロードして利用するとよい。

実験:

コマンドメッセージ next と reset 数値 応じて挙動を切り替える、新しい make a counter オブジェクトを生成して

ask コマンドで、コマンドメッセージを与えて、動作を確認する。

※ make a counter を生成し忘れると、 ask の実行時にエラーになる。

2018年度 第5回はここまで。次回は続きから。

P.59 C. Inheritance via Delegation

SNAPのカスタムブロックで他のオブジェクトにメッセージを移譲して処理させる。

移譲: あるオブジェクトに対する処理の依頼(メッセージ)を、別のオブジェクトに受け渡して処理をそのオブジェクトに任せること

継承: オブジェクト間に親子関係がある時、子のオブジェクトが親のオブジェクトの機能を利用して処理できる。機能の継承。

ここで以下のオブジェクトを作成する。

counterオブジェクト を内部で利用して7回目のカウントでブザーを鳴らす buzzerオブジェクト

マニュアル(Ver 4.1)の通りにプログラムすると、以下のようなエラーがでる。

※buzzer オブジェクトの動作確認で、 以下の様に ask する際にダミーの引数を指定しないとエラーが出る。

上記のエラーの原因は、SNAP!の仕様。

make a counter オブジェクトとは異なり、

make a buzzer オブジェクトは、内部で他のオブジェクト make a counter を利用している。

このため、make a buzzer オブジェクトの内部には、 ask ブロックが存在する。

ask ブロックで、next メッセージを引数無しで指定すると、空の可変長引数リストを指定したことになる。

その場合、

https://github.com/jmoenig/Snap--Build-Your-Own-Blocks/issues/1245

リング化されたブロック(今回は make a buzzer )の内部の空の可変長引数リストは、暗黙の書式パラメータ(リングの引数)になる。

リング内のブロックに、空の可変長引数がある場合、リングの呼び出し側で引数を与える必要がある。未指定にはできない。

その為、上記画像の左側の様に make a buzzerオブジェクトを next だけで呼ぶと、引数の個数が足らなくなり、エラーになる。

リング内部に、空の可変長引数ブロックがが有る場合の 呼び出し実験:

対処法(その1)

P.59の buzzer ブロックの定義を変更して対応する。

ask ブロックの引数にダミーの空スロットを追加

対処法(その2)

ask の仕様を変更して対応する。

修正前の ask の引数 オブジェクト メソッド 可変長引数(0~複数個)

修正後の ask の引数 オブジェクト メソッド 引数リスト(1個。リスト内に複数のパラメータを列挙)

あわせて counter の仕様も変更する。

修正前 メソッドの引数は、呼び出し元の可変長引数からリングの引数に割り当てられたものを使用

修正後 メソッドの引数は、呼び出し元の引数リストからリングの引数(1個)に渡されたものを取り出して使用

第5回SNAP4回目の終了分とaskの仕様変更まで作業済みのファイルを、このページに添付しておく。

SNAP!の課題(4/4回目) としてスクリーンショットをWebclassに提出。

スクリーンの様子

応用

P.60 D. An Implementation of Prototyping OOP

プロトタイプベースのOOPの実装

OOPのクラスは使用しない。

最初に作成したオブジェクト自体でクラスを表現する。

オブジェクトのインスタンスの作成は、元のオブジェクトのクローンで実現する。

調べて見よう:

クラスベースのオブジェクト指向

プロトタイプベースのオブジェクト指向

Viscuit は、プロトタイプベースのオブジェクト指向。

プロトタイプベースのオブジェクト指向を実装して、動作を確認をする。

作業済みファイルを 第6回SNAPでOOP として第6回のページに添付しておく。DLしてインポートして利用する。

P.58の ask ブロックの使い方ではエラーになるので↓の用に修正したものを用意した。

P.61の clone of ブロックに修正を加えたものを用意した。。

オブジェクトに inspect メッセージを加え、オブジェクトの内部状態を観察できるようになっている。

実験)

プロトタイプベース のオブジェクト指向システムの動作確認

※オブジェクト指向のシステムには次の2種類がある

・Java などの クラス定義と継承を基にした、クラスベース のものと

・JavaScriptなどの オブジェクト自身を雛形として利用する、プロトタイプベース のものがある。

以下のSNAPによるプロトタイプベースのOOPシステムで、次の内容を実行しながら確認する。

オブジェクトのカプセル化

・オブジェクトに プロパティ(データ) と メソッド(プログラム) を登録する仕組み

・オブジェクトの プロパティから値を取得する仕組み

・オブジェクトに メッセージを送って 引数を処理させる仕組み (メソッドの呼び出し)

・プロトタイプオブジェクトからクローンのオブジェクトを生成し、それぞれ別のオブジェクトとして動作する仕組み(インスタンス変数)

・プロトタイプオブジェクトから派生したオブジェクトに共通のプロパティの仕組み(クラス変数)

オブジェクトの親子関係(継承)

・派生オブジェクトで上書きもしくは独自に用意されていないプロパティやメソッドはプロトタイプのものが使用される仕組み

・派生オブジェクトに独自のプロパティとメソッドを追加する仕組み

・派生オブジェクトでプロトタイプに存在しているプロパティやメソッドを上書き(オーバーライド)してカスタマイズする仕組み

・派生オブジェクトでプロトタイプのメソッドをオーバーライドし、元のプロトタイプのメソッドを利用しながら一部をカスタマイズする仕組み

動作確認をしている様子:

以下は、2018年度は触れていない。

・引数固定のブロック

・リストを引数に取るブロック

・可変長引数のブロック

・畳み込み演算