Ruby で内部クラスを private にする
Ruby で内部クラスを private にする場合どうするのがよいかと思っていたんですが private_constant
を使うのがいいみたい。
private_constant があるのでそれを使えばそれっぽい気がします https://t.co/79ySXXyQ7l
— Pocke(ぽっけ) (@p_ck_) 2017年8月8日
class X class A end class B end private_constant :B def self.B_new B.new end end # OK X::A.new # Error: private constant X::B referenced (NameError) # X::B # OK X.B_new
Ruby の hook メソッド一覧
Ruby から呼ばれる hook メソッドの一覧が欲しかったので Ruby 2.4 時点で定義されているメソッドをまとめてみました。
他にもあればコメント等で教えていただけると助かります。
Class クラス
- #inherited
- クラスのサブクラスが定義されたとき
Module クラス
-
- 定義されていない定数を参照したとき
-
- self が他のオブジェクト に Object#extend されたとき
-
- self が Module#include されたとき
-
- メソッド name が追加されたとき
-
- メソッドが Module#remove_method により削除された時
-
- このモジュールのインスタンスメソッド name が Module#undef_method によって削除されるか、 undef 文により未定義にされるとき
BasicObject クラス
-
- 呼びだされたメソッドが定義されていなかったとき
-
- 特異メソッドが追加されたとき
-
- 特異メソッドが Module#remove_method により削除されたとき
-
- 特異メソッドが Module#undef_method または undef により未定義にされたとき
最新版の Vim で :terminal コマンドを使えるようにする
Scala でライフゲームを書いてみた
2〜3時間で軽く書いてみました。
初めて Scala をガッツリ書いたのであまり Scala らしさが感じられないコードですが…。
[コード]
import scala.sys.process._ object Lifegame { type Table = List[List[Boolean]] val o = false val x = true def width(table: Table) = { table(0).size } def height(table: Table) = { table.size } def at_cell(table: Table, x: Int, y: Int) = { if(x < 0 || width(table) <= x) o else if(y < 0 || height(table) <= y) o else table(y)(x) } def dead_or_alive(table: Table, x: Int, y: Int) = { val cell = at_cell(table, x, y) val count = List( at_cell(table, x - 1, y - 1), at_cell(table, x - 0, y - 1), at_cell(table, x + 1, y - 1), at_cell(table, x + 1, y - 0), at_cell(table, x + 1, y + 1), at_cell(table, x - 0, y + 1), at_cell(table, x - 1, y + 1), at_cell(table, x - 1, y - 0) ).count(x => x) if(cell) count == 3 || count == 2 else count == 3 } def update(table: Table) = { table.zipWithIndex.map { case(row, y) => row.zipWithIndex.map { case(cell, x) => dead_or_alive(table, x, y) } } } def print(table: Table) = { Process("clear").run println(Range(0, width(table) + 2).map(x => "-").mkString) println(table.map(row => "|" + row.map(x => if(x) "*" else " " ).mkString).mkString("|\n") + "|") println(Range(0, width(table) + 2).map(x => "-").mkString) Console.flush() } def run(table: Table):Int = { print(table) Thread.sleep(500) run(update(table)) return 0 } def main(args: Array[String]) { val table = List( List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o), List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o), List(o, o, o, o, o, o, o, o, x, o, o, o, o, o, o, o, o, o, o, o, o, o, o), List(o, o, o, o, o, o, x, o, x, x, o, o, o, o, o, o, o, o, o, o, o, o, o), List(o, o, o, o, o, o, x, o, x, o, o, o, o, o, o, o, o, o, o, o, o, o, o), List(o, o, o, o, o, o, x, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o), List(o, o, o, o, x, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o), List(o, o, x, o, x, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o), List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o), List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o), List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o), List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o), List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o), List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o), List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o), List(o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o, o) ) run(table) } }
[所感]
要所要所でつまずいたものの、全体的にみればそこまで難しくなかったかなーという感じです。
まあ元々 C++ の実装をそのまま Scala で書きなおしただけですしね(なので Scala らしさがあまりないとも言える
型に関しては C++ よりも厳しいという印象を受けました。
本当は List[List[Boolean]]
という型に依存したくなかったんですが、上手く消すことが出来なかった…。
ダックタイピングするだけでも結構いろいろと記述必要があるぽいのがちょっと厳しい…(良し悪しは別として。
Scala は他にはパターンマッチや trait、Structural Subtyping、implicit あたりなど面白い機能があるぽいので、次 Scala を書くときはそのあたりを少し意識してかいてみたい。
[気になったところ]
C++ でライフゲームを書いてみた
特に意味はないんですが、C++ でライフゲームを書いてみました。
C++14 で動作します(Windows での動作は未確認。
[コード]
#include <cstdlib> #include <thread> #include <string> #include <iostream> #include <vector> int main(){ using table_t = std::vector<std::vector<bool>>; table_t table = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, }; auto width = [](auto const& table){ return table[0].size(); }; auto height = [](auto const& table){ return table.size(); }; auto at_cell = [&](auto const& table, auto x, auto y){ return x < 0 || width(table) <= x ? false : y < 0 || height(table) <= y ? false : table[y][x]; }; auto dead_or_alive = [&](auto table, auto x, auto y){ auto cell = at_cell(table, x, y); auto count = at_cell(table, x - 1, y - 1) + at_cell(table, x - 0, y - 1) + at_cell(table, x + 1, y - 1) + at_cell(table, x + 1, y - 0) + at_cell(table, x + 1, y + 1) + at_cell(table, x - 0, y + 1) + at_cell(table, x - 1, y + 1) + at_cell(table, x - 1, y - 0); return cell ? count == 3 || count == 2 : count == 3; }; auto update = [&](auto const& table){ table_t result = table; for(int y = 0 ; y < table.size() ; ++y){ for(int x = 0 ; x < table[y].size() ; ++x){ result[y][x] = dead_or_alive(table, x, y); } } return result; }; auto print = [&](auto const& table){ std::system("clear"); // or // std::system("cls"); std::cout << std::string(width(table) + 2, '-') << "\n"; for(auto&& row : table){ std::cout << "|"; for(auto&& cell : row){ std::cout << (cell ? "*" : " "); } std::cout << "|\n"; } std::cout << std::string(width(table) + 2, '-') << "\n"; std::cout << std::endl; }; while(1){ print(table); table = update(table); std::this_thread::sleep_for(std::chrono::milliseconds(500)); } return 0; }
[動作]
C++ だと実装するのが難しいと思いましたが、実際に書いてみるとそこまで複雑なコードにはならなかった。
上のコードだと100行もありませんし、短くしようと思えばもっと短くできそう。
鬼門なのは『接するセル』をどうやって走査するかですかね。
今回は愚直に実装しましたが、もっとスマートなやり方はありそう。
とりあえず、標準ライブラリに Range がほしい。
Ruby の (1..5) と (1...5) の違い
前者は使っていたけど、後者は知らなかかったので覚書。
範囲演算子 ..
を使用した場合は終端を含み、...
を使用した場合は終端を含みません。
p (1..5).to_a # => [1, 2, 3, 4, 5] p (1...5).to_a # => [1, 2, 3, 4]
C++14(17) で zip 書いてみた
現状の C++ で zip を書いたらどうなるんだろう、と思って書いてみました。
[コード]
#include <iostream> #include <algorithm> #include <vector> #include <tuple> template<typename T, typename U> constexpr auto zip_impl(T v1, U v2){ auto vi1 = std::begin(v1); auto vi2 = std::begin(v2); using value_t = decltype(std::make_tuple(*vi1, *vi2)); std::vector<value_t> result{}; while(vi1 != std::end(v1) && vi2 != std::end(v2)){ result.emplace_back(*vi1, *vi2); vi1++; vi2++; } return result; } template<typename T, typename U> constexpr auto zip(T v1, U v2){ return zip_impl(v1, v2); } template<typename T, typename U> constexpr auto zip(std::initializer_list<T> v1, std::initializer_list<U> v2){ return zip_impl(v1, v2); } int main(){ for(auto [x, y] : zip({1, 2, 3, 4, 5}, {'a', 'b', 'c', 'd', 'e'})){ std::cout << x << ":" << y << std::endl; } return 0; }
[出力]
1:a 2:b 3:c 4:d 5:e
https://wandbox.org/permlink/qQEvmwNMjgVt3GHJ
手癖で constexpr
をつけているけど特に constexpr
ではない(std::vector
に依存してるので constexpr
には出来ない…。
使う側では C++17 の『構造化束縛』を使っているけど、実装側は C++14 でも動作すると思う。
っていうか、range based-for で構造化束縛使うのかなり強力なのではないだろうか???
実装は単純に2つのコンテナを iterator で回しながらタプルで保持するようにしてるだけですね。
特に複雑なことはしていないと思う。
最適解かどうかは別としてこういうコードが C++ でも雑に書けるようになったのはだいぶよさがあるなあ。