"piyo"doの後にインデントして二つのモナド関数を並べるだけで順に実行(合成)されます。一般的に書くと以下の形になります。doIOモナドIOモナド・・・IOモナドこの形はIOモナド以外の他のモナドでも同じです。doStateモナドStateモナド・・・StateモナドとかdoEvalモナドEvalモナド・・・Evalモナドなどです。do記法を使うと普通の手続き言語のように、上から順番にモナド関数を実行するという書き方ができるのです。以下のように異なるモナドを混ぜて書くことはできません。doでまとめられるのは一種類のモナドだけです。()というIOモナド(を生み出す)関数は置けません。なり、めでたくIOモナドとして並べることができます。面白いことにモナドを並べてdoでまとめたものは、それ自体が一つのモナドになるのです。"piyo"これで一つのIOモナドになります。こんな書き方もできます。"mooo”それではdo記法について覚えることの2つ目です。getLineというIOモナド関数の型を思い出して下さい。doの中ではIOで包まれた中身の型のデータを取り出すことができます。<-という記号を使って以下のように取り出せます。”doの中でだけ取り出せる”ということを頭の片隅に入れておいて下さい。StringというIOモナドなので、lineはString型の値です。getLineの部分でキーボードからの入力を待っています。文字列を入力してエンターをッターンすると、lineに文字列が取り出されます(束縛)。putStrLnに渡してまた画面に表示しているというわけです。以下はちょっと中途半端ですがEvalモナドの例です。いう関数のつもりです。Intなどの中身を取り出せるということです。do記法について覚えることの3つ目にまいりましょう。今度は逆に普通の値をdoの中でモナドに包み込む方法です。returnを使います。Stringという型になりIOに包まれます。純粋な値もIOで包んでIOモナドにすることでdoの中に並べることができるようになるのです。これまたややこしいのですが、普通の言語でreturnと言ったら”関数から戻る/抜ける”という意味ですが、Haskellでは”普通の値をモナドに包む”という意味だけです。doの中から外に出られるわけではありません。lineで終了してしまうなんてことにはならず、ちゃんと最後まで順に実行されます。ヘンテコなコードですが、こんな感じにも使います。combinedlinedo記法について覚えることの4つ目は、純粋な関数の呼び出しとモナドを混ぜる方法です。line2reverse関数は[a]->[a]という型の純粋な関数です。純粋関数」と書くと純粋関数を呼び出し、その戻り値を変数に束縛できます。以上がモナドの使い方の基本的なところです。まとめると、1モナド関数の見極め方2do記法の中でモナドの並べ方(合成)3do記法の中でモナドに包まれた値の取り出し方4do記法の中で値をモナドに包むやり方5do記法の中で純粋関数を呼び出すやり方を覚えていただければと思います。前回のGUIコードを再掲してもう一度読んでみます。doの中で1行ずつIOモナドを並べ、一つの大きなIOモナドに合成したものをmainと定義しているのです。次にinitGUIやmainGUIを見てください。()という引数なしのIOモナド関数、つまりIOモナド値そのものを並べているだけなのです。次にwindowNewを見てみます。WindowというIOモナドから中身のwindowを取り出していることが分かります。windowSetTitleやwidgetShowAllは折角なのでghciで型を調べてみてください。()を作るモナド関数であることが分かると思います。`on`〜の部分が残りました。ここが最も難しいところです。onという関数の型を調べてみましょう。object)となっています。眺めれば読み取れることがあります。(ほにゃらら)なのでIOモナド関数であることが分かります。on関数の引数の数は3つであることも分かります。」という型のようですね。一度サンプルコードを見ます。onは`on`とバッククォートで囲んで中置演算子のように書いています。このテクニックは初出かもしれませんね。文字から始まる関数(onやdivやmod)を中置にして+や*のような2項演算子にしたい場合にバッククォートで囲みます。deleteEventと同じことです。一個のテクニックを紹介します。$は関数の結合優先順を変えるものです。括弧で結合の様子を表してみると少し分かりやすくなります。いう風にon関数の第3引数にdoという関数(?)を渡していることになりコンパイルエラーとなります。do以降のコードの塊をonの引数に渡せます。これらのテクニックについては説明不足ですがこの辺にしておきます。重要なのは、on関数の第2引数に渡しているのがdeleteEvent関数である点です。deleteEvent関数の型を見てみましょう。複雑そうです・・が、これもじっくり眺めましょう。=>より前の部分はselfに対する型クラス制限ですのでここでは無視します。」という型なので、onの型宣言の第2引数とぴったり合っていることが分かりますね。onの定義をもう一度見ましょう。Signalの2つ目の型変数callbackと、onの第3引数のcallbackは型変数名が同じなので同じ型が入ることが分かります。Bool)型であることが分かりました。onの第3引数の姿が見えてきましたね。EventMという名前のMはモナドのMです。このネーミングルールは慣習なのでHaskellに慣れて勘を働かせるしかありませんが、onの第3引数にはイベントモナドというモナドを渡すようです。どんな機能があるモナドか詳しく調べていないのでここで解説できませんが、とにかくモナドなのでdo記法が使えるはずです。EventMモナドを並べたり、EventMモナドの中身を取り出したり、普通の値をreturnで包んでEventMモナド化する、といった前述1〜5のテクニックはIOモナドだけでなくEventMモナドでも通用します。さあ、大分ごちゃごちゃしてきましたが、もう一度問題のコードを見ましょう。mainQuitは無視しましょう。Falseこう見れば、純粋な値(Bool)をreturnでEventMに包んでEventMモナドを作り、onの第3引数に渡していると読み取れますでしょうか。mainQuitの部分を解説します。()ですのでIOモナドです。ところが今書いているdoはEventMモナドですね。モナドの合成で説明した通り、異なるモナドをdoの中で並べることはできません。そこでliftIOの登場です。liftIOはIOモナドを別のモナド、ここではEventMモナドに変換する関数です。いった変換を「持ち上げる(lift)」と呼ぶ慣習がありliftIOという名前が付いています。今回、変換の仕組みまでは紹介できませんが、興味のある方は”モナド変換”や”モナド変換子”を調べてみて下さい。mainQuitと書くことで、IOモナドの処理(イベントループ終了処理)を、立派なEventMモナドに変換することができ、無事doの中で並べることができました。ここまで読んで頂いた方、お付き合い有難うございました。モナドの使い方に焦点を当て、do記法が分かれば何とかGUIサンプルコードも読めるぞい!ということを説明したかったのです。C言語のポインタしかり、Javaのクラスベース開発しかり、Haskellのモナドもきっと読むだけではよく分からないと思います。モナドに興味のある方は是非Haskellをインストールしてモナド関数に触ってみて下さい。様々なモナドに精通するのはなかなか難しいですが、まずはIOモナドをdo記法の中で使うことに慣れましょう。IOモナドが使えるとHaskellで色々なことができるようになりますので、是非楽しんで下さい。次回からテトリス作成に入っていきたいと思います。最後に、モナドの仕組みに興味がある方には「すごいHaskellたのしく学ぼう!」という書籍がオススメです。モナドの説明がとても分かりやすいです。Haskell)をWebで読むことができます。http://learnyouahaskell.com以上。第33回目:Haskellでテトリス(Part1)2014-11-02筆者:村田こんにちは。今回からまたHaskellにチャレンジしたいと思います。Euler問題に取り組んで以来となります。前回は再帰を使ったループ処理や、計算の型を考えながらのプログラミングといったテーマを扱いました。忘れちゃっているかもしれませんが、Haskellを触りながらゆっくり思い出したいと思います。それではしばらくお付き合い宜しくお願いいたします。テトリスについては説明不要なので早速ゲーム作り開始といきたいところですが、Part1のテーマは環境準備です。Part2ではdo記法を用いたモナドの使い方をテーマにする予定でして、具体的なテトリス作成はもう少し先になります。純粋関数型言語と呼ばれるHaskellでは入出力のような副作用の扱いに癖があり、ゲームのようなイベントドリブン処理と純粋関数を結びつける部分が少々難しいのです。具体的にはモナド(Monad)という仕組みを使うのですが、これが何といいいますか・・・とっつきにくいシロモノなのです。ひとことで言えば『文脈付き計算の合成』という感じなんですが、きちんと説明できるほど私が理解していないので、理論/仕組みについてはWebや書籍を参考にしてください。新しいモナドを生み出すのではなく、とりあえずIOモナドを使うだけならば仕組みに詳しくなくても何とかなります。私の場合も色々ネットのコードをコピペして、いじくって、コンパイルエラーと格闘して、な〜んとなく使っているという感じです;-)それでは環境準備を始めましょう。OSはMacOSXかLinux(Ubuntu14.04)を前提に進めます。Windowsでもできると思いますがまだ試していません。テトリス完成までにWindows版環境構築も情報展開できるかもしれませんが今のところ未定です。関係無い話ですがWindows8.1にしてからあまり触らなくなってしまいました。操作に慣れなくて・・・。(現在のバージョンは2014.2.0.0)をインストールしてください。問題はGUI画面を作るためのライブラリ(ToolKit)をどうするかです。Platformに付いてくるGLUTを使うこともできますがOpenGLに精通していないとキツそうです。調べてみると結構色々なライブラリがあるのですが、有名どころはGtk2Hs、HGL、wxHaskellあたりでしょうか。どれを使ってもテトリスを作れると思いますし、それぞれ書き方や思想が異なるので色々触ってみてお気に入りを選んでもらえば良いのですが、今回はGtk2Hsを使いたいと思います。こいつのインストールが結構大変です。こちらのサイトhttps://www.haskell.org/haskellwiki/Gtk2Hs/Installationの通りに進めれば良いのですが、結構記述が分散していて分かりにくいので、以下に私の環境で行った手順をメモしておきます。100%うまくいくとは限らないので、トラブルがあったらgoogle先生に聞いてみましょう。updateここでハマることがあります。Codec.Compression.Zlib〜というエラーがでる場合はリポジトリデータのダウンロードに失敗しています。一度このエラーが出ると再度updateしてもうまくいきません。~/.cabal/packags/hackage.haskell.orgを全部削除して再度試してください。updateに失敗するのです。gtkそれでは以下のサンプルコードをGtkHello.hsとして書いて動作確認してみます。windowmainGUIコンパイルして実行してみましょう。./GtkHelloウインドウが無事表示できましたか?おめでとうございます、8888。上記のコードをちょっと眺めてみてください。これはモナドを使ったコードです。分からないところもあると思いますが、何となくわかる部分も結構ありませんか?個人的にはよく分からないコードを眺める瞬間が好きです。文法とかは置いておいて色々想像するのが楽しいからです。全部分かるコードより、ちょっと分かるくらいのコードが妄想にちょうどいいのです。分かるところから壊していくのも楽しいです。私なら上記のコードが初見だったら・・まずはハローワールドの部分を書き換えてタイトルが変わることを試します。次に一行ずつコメントアウトしてもっとミニマムにできないか、必須なのはどこか、役割を想像しながら実験します。Falseも気になりますね。Trueに変えてもコンパイルが通りそうですし、値を変えて試すのは基本ですね。$や<-などのシンボルを消したりしたら、きっとコンパイルできないでしょう。どんなエラーがでるか試してみたくなります。その後はマニュアルを紐解きながら遊べそうです。deleteEventってイベントを定義できるコードっぽいですね。〜って書けばハンドラが書けるっぽい。何か別のイベントを拾ってハンドラを付け加えてみたくなります。マニュアルでほにゃららEventって名前の関数を探してみたり・・と、まあ上記のコードは短すぎてそのくらいで飽きるかもしれませんが、ネットにはたくさんのサンプルコードがあるのでもっと良いコードをいじくることをお勧めします。以下はGtk2hsのdemoコードです。古いのでコンパイルエラーが出るコードもありますが、コメントアウトで凌ぐか、頑張って直してみるのも一興です。http://code.haskell.org/gtk2hs/gtk/demo/今回はここまでにします。次回Part2ではモナドの『使い方』(理論とか仕組みの話ではありません)についてお話ししたいと思います。第32回目:Processingでシューティング(Part4)2014-10-18筆者:村田こんにちは。Processing.jsというJavaScriptのライブラリを使うとProcessingをブラウザのcanvas上で動かすことができます。公式サイトのリファレンスを見るとファイル操作関連を除いてProcessingAPIがほぼそのまま動くようです。面白そうなので紹介したいと思います。(または軽量版processing.min.js)をダウンロードします。同じディレクトリに以下のHTMLを書いてブラウザで開いてみて下さい。ブラウザはSafari7.1で動作確認しています。id="canvas"></canvas></body></html>canvasの中央に水色で円が描かれましたか?このようにProcessingのコードがそのまま動いちゃいます。楽しいライブラリですね。上記はProcessingの文法で書いていますが、JavaScriptの方が好きな方は以下のようにJavaScriptで書くこともできます。id="canvas"></canvas></body></html>というわけで前回作ったシューティングプログラムをprocessing.jsを使ってWebにUpしてみました。以下のURLを開き、ゲーム画面を一回クリックすると上下左右キーでプレイヤーを操作できると思います。・Shootinghttp://muratamuu.github.io/Processing-ShootingGame/index.html今回おまけ編で、もうチョイProcessingっぽいものを作ってみようかなと思いまして、あと一本プログラムを書いてこちらもWebにUpしました。以下のURLを開いて画面をクリックしてみてください。カラフルなにょろにょろがマウスポインタのそばに寄ってきてくるくる回ったりします。Nyorohttp://muratamuu.github.io/Processing-RainbowNyoro/index.htmlどうでしょう?ちょっとキモイかもしれません・・・。コードに興味のある方はブラウザの右クリックでHTMLソースを表示させてみれば中身を見ることができます。[おわりに]Processingはいかがでしたか?簡単にビジュアライゼーションできて遊べるとても楽しい言語だと思いました。プログラムの構造化などはあまり気にせずガンガン書いてみて、RUNしてちょっとパラメータいじって・・の繰り返しで結構ハマります。3Dや音楽なども扱えるので、プログラミングでアートしてみたい方はProcessingをお試しあれ。日曜は情報処理試験ですね。Nyoro2014-10-18第31回目:Processingでシューティング(Part3)2014-10-12筆者:村田こんにちは。今回はプレイヤーを表示させるところから始めましょう。プレイヤーも敵と同じようにクラスにまとめます。y+10);}}Playerのdrawメソッドで三角形を描いています。triangleの引数は3つの頂点のx,y座標です。三角形の中心をx,yとし、幅、高さは20とした場合の3つの頂点を考えます。1つ目の頂点は(x,y-10)となります。Processingの座標系はY軸が画面上がマイナスであることに注意して下さい。残りの2点は(x-10,y+10)、(x+10,y+10)となります。次は上下左右キーでプレイヤーを移動できるようにしたいと思います。マウス位置はグローバル変数mouseX,mouseYに入っていましたが、キーボードの値はグローバル変数keyCodeを参照して取得します。それと、キーを押している間だけプレイヤーが移動し、離したら止まるようにしたいですね。これもイベントハンドラを書く必要はなく、グローバル変数keyPressedを参照しtrue/falseで判断できます。Playerクラスのmoveメソッドを実装しましょう。height-10;}...}ではPlayerオブジェクトを作って画面に表示させましょう。プレイヤーは緑色の三角形player.move();player.draw();}実行すると参考画像1のようにプレイヤーを上下左右キーで移動できるようになりました。次はプレイヤーもレーザー弾を発射できるようにします。今回は弾は自動発射にしようと思います。プレイヤーの弾も速度を与えて一定方向に移動するので、前回の弾クラス(Bullet)がそのまま流用できそうです。図形をちょっとレーザーっぽくしましょう。いうわけで、Bulletクラスを継承してLaserクラスを作ります。レーザー弾は長方形}}継承はJavaと同じでextendsで書きます。それではLaserコンストラクタを見ていきます。弾速度と角速度を固定値にしてBulletクラスのコンストラクタを呼びます。スーパークラス(Bullet)はsuperで参照できます。Laserは長方形の図形にしますので、幅と高さはコンストラクタのパラメータでもらいましょう。次にレーザー弾もリストで管理しましょう。Bulletと同じように画面外に出たら削除します。以下のコードは前回のBulletリストのコードをコピペして作りました。画面外のレーザーは削除}...}これでレーザー弾の描画は行えるようになりました。あとはPlayerクラスが適当なタイミングでレーザー弾を発射できるようにしましょう。幅20/高2}}これで参考画像2のようにレーザー弾が出るようになりました。次は当たり判定を実装しましょう。BulletとPlayer、LaserとEnemyと2つの当たり判定があるので、共通関数として衝突判定関数を作りましょう。true;}まず引数で2つの長方形(x,y,w,h)をもらいます。この2つの長方形が「重ならない」条件を考えていく方法が簡単です。最初のif条件を見ます。w1/2とは「中心+幅の半分」つまり長方形1の右端ですね。w2/2は「中心ー幅の半分」つまり長方形2の左端です。長方形2の左端」という状態をイメージできますか?このとき2つの長方形は絶対に重ならないのです。いうことでfalseを返しましょう。2つ目のif条件は長方形1と長方形2の位置関係を入れ替えたものです。長方形1の左端」ならば重なりません(false)。3つ目のif条件を見ます。h1/2とは「中心+高さの半分」つまり長方形1の下端です。h2/2とは「中心ー高さの半分」つまり長方形2の上端です。長方形2の上端」という状態をイメージして下さい。これも2つの長方形が絶対に重ならない状態です。4つ目のif条件は長方形1と2を入れ替えた条件ですね。最後にこの4つの条件を満たさない場合は「重なっている」のでtrueを返します。弾が当たったら敵/プレイヤーそれぞれHPを減らすようにしましょう。EnemyとPlayerクラスにそれぞれHP属性を加えておきましょう。いわゆるsetter/getterアクセサは作りません。10;...}衝突関数を使って敵の弾が当たったかを判定する箇所ですが、draw関数の中で弾リストを表示しているところで判定しちゃいましょう。bulletList.remove(i);}...}ループの中でplayerとbulletの衝突判定を行っています。本記事最初でPlayerの緑三角形の幅と高さを20x20としていましたが、当たり判定に使う矩形を3x3と小さくすることで弾を避け易くしています。弾に当たったらbullet.hitをtrueにします。前回の記事の通り、bullet.needRemove()がtrueを返すようになりますので、playerに当たった弾は消えることになります。同じようにenemyとlaserの衝突判定も書きましょう。true;enemy.hitPoint--;}...}...}敵さんの当たり判定サイズは20x20です。次はHitPointを画面に表示させましょう。ゲームオーバー}text関数を使って画面に文字列を表示することができます。第1引数に文字列を渡します。文字列はJavaのStringと同じです。Processingのnf関数で数値を3桁の文字列に変換しています。第2,3引数は表示する座標です。最後にプレイヤーか敵のHPが0になったらnoLoop関数で描画ループを止めてゲームを終了します。遊んでみると敵の弾に当たらない安全地帯があることが分かりました。そこに入ってしまえば手を止めていてもいずれ勝ってしまうのです。うーん、もう少し頑張りましょうかね。敵がプレイヤーを狙い撃ちしてくるスナイパー弾を追加しましょう。うーんこのネーミングもイマイチ・・。狙い撃ちとは敵とプレイヤーを結ぶ線の角度で撃ってくる弾です。プレイヤーを直接狙った弾ってことです。このようにA地点とB地点を結ぶ線の角度を求める場合、三角関数のatan(アークタンジェント)を使うのが定石です。サイン・コサイン・タンジェントのタンジェントを思い出しましょう。tanは直角三角形の角度からxとyの比率が出せます。atan(アークタンジェント)はtanの逆関数ですので、xとyの比率から角度が出せます。atan(1/(ルート3))は30°になります。えっと実際に使ってみた方が早いです。0);bulletList.add(bullet);}}まず敵から見たプレイヤーの相対位置dx,dyを計算します。player.xではありませんので注意。atan2(dy,dx)でxとyの比率から角度(ラジアン)を計算します。ラジアンから度数に変換するためdegrees関数を通してからBulletを生成します。atan2関数はxとyを2引数で渡しますが第1引数がy、第2引数がxであることに注意しましょう。アークタンジェントを1引数で計算するatan関数を使う場合はatan(dy/dx)となります。これで安全地帯は無くなり、じっとしていると敵のスナイプ弾を食らってしまうようになりました。今回のシューティングゲームはここまでになります。ソースコード全体は以下のGitHubを参照してください。Death」をちらっと見ました。死にゆく言語としてPerl/Ruby/VB.Net/ActionScript/Delphiの5言語が挙げられています。Rubyが入っていることに驚きました。Twitterの開発言語がRuby(RoR)からScalaに置き換えられた理由でもあるパフォーマンスの問題を指摘しています。これだけでRuby終わったと言ってしまうのも・・と思いましたが、まあそれはさておき、いずれもとても人気のあった言語です。新規プロジェクトで使われる機会が減っているのかもしれませんが、既存の資産としては結構な量のコードがあるのではないでしょうか。World!”には早いですよね。