読者です 読者をやめる 読者になる 読者になる

AccessViolation Exception

仕事でもはんだづけ、家でもはんだづけ

Scalaっぽく迷路をリファクタリングしてみる(穴掘り法)

この記事は前記事

Scalaで迷路を作ってみる(穴掘り法) - AccessViolation Exception

リファクタリングとなります

Scalaっぽく?


  • 別にこの実装ならc#で書けんじゃん
    • match,implicitぐらいしか使ってなくね
    • むしろvalとvar周りでうまく設計できてなくね
    • というかmap1 intersect map2どうやって実装すんのかわかんねぇ
  • 調べるとすごく便利そうな機能あんじゃん
    • 特に型周りに境界が設けられる
    • 暗黙の~的なもの
  • そういえばc#の拡張メソッド的なものはどうやるんだろうか
static class IntExtension 
{ 
    public static int Twice(this int x) { return x * 2} 
}

を定義すると 100.Twice()//200 と出来るやつ

c#でできることができないみたいなことに腹を立てたのでリファクタリングしました。 参考にしたのは某書籍と

Scala 2.10.0 M3の新機能を試してみる(3) - SIP-15 - Value Classes - kmizuの日記

こちらです。大変参考になりました。

ともあれやってみる。以前のコードは前記事を参考に

(c#で言うところの) 拡張メソッドを実装したい


printMaze(dst)はださい。駅ホームの階段で転ぶくらいださい

implicit classでメソッドを追加する

implicit class Maze(val self:Map[(Int,Int),String])を定義してメソッドを追加することでMap[(Int,Int),String]型から呼ぶことを有効化できる

ただMaze型のクラスメソッドとなってしまうのでMap[(Int,Int),String]->Mazeの暗黙の型変換を用意してやると

implicit def mapToMaze(self:Map[(Int,Int),String]) : Maze = new Maze(self)

型変換が必要なときに勝手に読んでくれるのでmapToMaze(dst)を自分でやる必要はない

そんな感じでdst.drawで迷路が出力できるようになりました。

同じ要領で前回困っていたMapのintersectも

intersect(src,dig(arounds.head,src)(size))src intersect dig(arounds.head,src)(size)とできるようになった。

immutableな実装にする


関数型とは

純粋関数型言語では、参照透過性が常に保たれるという意味において、全ての式や関数は副作用を持たない。

関数型言語 - Wikipediaより

副作用のない実装といえば状態によって結果が変わらない。例えば円周はいかなる状態であれば2πrのようなもので内部に状態を持ってはいけない*1

既存の実装だとdig内のsrc,aroundsが状態を持っているので排除してみる

今まで
  • 今いる場所の4方を列挙
  • 4箇所全てに対して
    • その場所の壁を壊していいなら壊す

around filter(canDig) foreachで実装しなかったのはそこまでの結果でcanDigの結果が変化してしまうから。filterを先にしてしまうと結果が保証できなくなってしまう*2

リファクタリング
  • 予め関数が壊す場所のリストを受け取る
  • 無いなら壊す場所のリストを列挙する
  • 壊す場所のリストの先頭が壊せる

    • こわす
    • 今の場所から他の場所に伸ばせるなら伸ばす
  • 壊せない

    • 壊す場所のリストがまたあるならそこを壊してみる
    • ないなら終わり

に変えれば自己完結できてかつvarを排除することができた

まだまだ雑だけどもっと効率よく美しいコードを書いていきたい。

リファクタリング:scalaで迷路(穴掘り法)

*1:モナドとか詳しいことが入ると消されます

*2:いま思うとこのような実装が複雑さを生むのかもしれない