あせらず、ちょっとずつ読んでいくつもり。
ケーススタディとかは、答え合わせをさぼったり、がんばりを後回しに保留したりとかする感じで。
Ruby
象徴的。
彼が関心があるのは、プログラマの生産効率の最適化に関心である。
読み進めつつメモ 1日目
・ブロックの概念が設計者のお気に入り
・スレッドを廃止してアクターやその他の高度な並列機能を追加したいとのこと
・まず対話コンソールをつかうといい
・バイトコードにコンパイルする仮想マシンの開発もある
・実行にはかならず値が返ってくる
・文字列リテラルの変数は置換で埋め込まれる
・うわ、Rubyでは数値もオブジェクト
・条件文は行末に書く修飾子もあるのね、処理を書いてから分岐を考える場合には便利なのか
・unlessの方が可読性が良いらしい
・数値の0はtrue評価
・論理演算子は左から評価
・&または|で式全体を実行して比較
・強く型付けされたように振る舞うが、型安全性を破壊することも可能
・動的型付け(関数実行時に型チェックを実行)となっている
・to_iメソッドの例のように、quackメソッドによって、ダックタイピングができる
irb楽しい
実践は省略、乳母とはぎこちなく会話できる感じ
もっとこの時点でいろいろ試してみるべきなのかも知れないがサボって次へ進もうっと
あと、序盤の文章の分からない単語も調べずに進んでいるので後々調べた方が良いかもっと
読み進めつつメモ 2日目
コレクション・シンボル・シンタックス
・順序付きコレクション(配列・ハッシュを含む)は有用な機能
・animals[-2]のような記述はシンタックスシュガーによるもの
・animals[0..2]のような記述はシンタックスシュガーによるものではなく、0..2はRange
つまり、コアシンタックスということなのかな。範囲演算子というらしい。
・[]はArrayクラスのメソッド
・[]と[]=は配列にアクセスするためのシンタックスシュガー
・シンボルは:symbolのようにコロンの識別子をつける
・シンボルは同じ名前の記述であれば一意で物理的に同じオブジェクトを表す
・文字列リテラルはそれが示す文字列が同じでも別オブジェクトであり得る
・関数の引数のブレース()は省略可能
・何でも配列、ハッシュキー、ハッシュ値に保持できるので高度なデータ構造体を作れる
・配列には多くのAPIが用意されている(配列オブジェクトのメソッドのこと?)
コードブロック・yield・クラス・オブジェクト
・コードブロックはRubyの本当の力を発揮させる
・コードブロックは無名関数で、関数やメソッドの引数としても渡せる
・1行のコードブロックはブレースで、複数ならdo/endで囲むのが慣習
・コードブロックの威力の片鱗は下記コードに現れる
animals.each {|a| puts a}
・ん??え??既存のクラスにメソッドを追加できる
class Fixnum
def my_times
i=self
while i>0
i=i-1
yield
end
end
end
・上記、yieldキーワードのタイミングで無名関数が実行されているが、
関数に引数をとることが明記されていないけどどのタイミングで実行するんだ??
yieldの言語処理系での違いについてググった。
なるほど。
rubyの場合は、C#とPythonと違い、渡されたブロックに値を送り込むというものです。
主従が異なるので、rubyは"逆"と覚えてください。
これは、
block.call
で置き換え可能ってこと??
・メソッドでブロックを引数にとるには&をつける
PHPだと参照の意味だけどRubyのこれは違うのかな。
ちなみに試しに先頭に&をつけないで関数の引数としてブロックを渡したらエラーになった。
class Fixnum
def my_times5 block
i=self
while i>0
i=i-1
block.call i
end
end
end
3.my_times5 {|n|puts "mangy moose #{n}"}
# test.rb:30:in `my_times5': wrong number of arguments (0 for 1) (ArgumentError)
・コードブロックには多くの用途がある
ファイルの各行を処理する、HTTP トランザクション内で処理を実行する、コレクションに対して複雑な演算を実行する
・クラスは全てObjectクラスから派生する
・オブジェクトはクラスから導出される
・クラスのインスタンスはオブジェクトのテンプレートとなる
・クラスのインスタンスはオブジェクトでもある
つまり、 クラス>インスタンス(クラスでありオブジェクト)>オブジェクト ってことかな。
クラスとオブジェクトの線引きはどうなってるんだ。jsのprototype的な何かあるのかな。
・Ruby1.9以降ではObjectのスーパークラスとしてBaseObjectがある
・クラスの初期化ではinitializeが呼ばれる
・インスタンス変数には@をつける
・クラス変数には@@をつける
・インスタンス変数の定義には attr と attr_accessor gaaru
あれ、クラス内メソッドをクラス内から呼び出すときにはthisとかselfとかいう指定の記述はなくていいのか。
スコープの外の関数とどう区別するのかな。優先順位は?スコープの指定も出来る?
モジュール・Mixin
PHPのtraitもそうだけど、モジュールの混ぜ込みの内部処理はどういう処理なのだろう。
そもそもクラスとかってどう処理されるのか。
・モジュールの概念があり、関数と定数の阿智真理で、クラスの一部として混ぜ込むことが出来る
挙動としてはPHPでいうtraitみたいなものかな。
違うかな、違うとするとどう違うのだろう。
モジュール内でもthisとかselfとかの指定の記述はないな。
・混ぜ込むことをMixinとよぶ
このプログラミングスタイルはmixinと呼ばれ、Flavorsで初めて導入され、SmalltalkやPythonなど多くの言語で使われている。
・Mixinしたクラスを継承したサブクラスもスーパークラスのMixinした実装を使うことが出来る
・Rubyで最も重要なmixinとして、EnumerableとComparableがある
・Enumerableをmixinする場合、eachを実装する必要がある
・Comparableをmixinする場合、宇宙船演算子<=>を実装する必要がある
Fixnumの宇宙船演算子の実装はどうなってるのか。
シンボルはなんかいいな。便利そう。
う、いろいろ保留しても二日目が長くて終わらない。。
二日目まとめ
このレベルの抽象化でも少しは優れたプログラミング言語になるが、Rubyの真の秘術が登場するのはまだまだこれからだ。
セルフスタディ
むむ、ちょっと分析的な思考が必要になるとのこと。
探してみよう
-
コードブロックの利点(ファイルアクセス)
- 概要の振り返り
- 関数の引数を用意しなくても呼び出せるyieldで(コードブロック以外に無名関数がある?)
- yieldでの処理受け渡し
- 可読性の向上
- ファイルオープンのストリームなど再利用をあまりしない場合には記述箇所が明確化(無名関数の利点)
- 記述性の向上
- ブレースで囲むだけでいい
- ストリームの変換処理などの限定した処理の受け渡しが可能(無名関数の受け渡しの利点)
- 処理をコードブロック側にゆだねてしまうことで柔軟に記述できる
- ブロックを使わない場合について
- 関数を定義したり、その名前空間に気を遣ったりすることがあるかもしれない
- 関数をトレースすればSDKなどで記述元を追える
- お約束的・慣習的な共通処理が再利用できる
- 指定や定義により手続が増えがちになるかも
- 概要の振り返り
-
ハッシュと配列の相互変換
- キャストをつかう
-
多分ある
test.rbirb(main):147:0> [['3','5']].to_h => {"3"=>"5"} irb(main):150:0> {3=>"hoge",8=>'b'}.to_a => [[3, "hoge"], [8, "b"]]
-
キャストの内部処理はどうしてるのか
-
- ループを回してクローンする
- each {}
- キャストをつかう
-
ハッシュの各要素のループ
- 例にあったTreeクラスの様にコードブロックを使う(再帰ループ)
- 例にあったEnumerableやComparableをMixinしてallメソッドを活用する
-
配列で可能なデータ構造体
- スタック
- シーケンス
試してみよう
問いの意図するところがいまいちわかってないかも。
- eachだけを使って出力
# ひとまず破壊的です
arr16 = [1,2,3,4,5,6,7,8,9,10,1,2,3,4,5,6]
arr4 = [1,2,3,4]
if arr4.length > arr16.length
arr4.each {|j|i=arr16.shift;puts "#{i} #{j}";}
else
arr16.each {|j|i=arr4.shift;puts "#{i} #{j}";}
end
- Enumerableを使って出力
わからんので調べたけど。。多分問題の意味するところを勘違いしてる。
(1..8).each_slice(3) {|arr| print "(" + arr.join(",") + ") " }
・Treeクラスを改善する
どうせなので継承についてはさくっとしらべた。
http://www.ruby.or.jp/ja/tech/development/ruby/tutorial/090_class_extension.html
class Tree
attr_accessor :children, :node_name
def initialize(name, children=[])
@children = children
@node_name = name
end
def visit_all(&block)
visit &block
children.each {|c| c.visit_all &block}
end
def visit(&block)
block.call self
end
end
ruby_tree = Tree.new("Ruby",[Tree.new("reia"),Tree.new("MacRuby")])
ruby_tree.visit {|node| puts node.node_name}
ruby_tree.visit_all {|node| puts node.node_name}
# できるだけ既存の構造を残す形にしてみる。できねー。ちゃんといろいろ調べないと無理だな。
# 日が変わってからやりなおしたらできた
quest = {
'grandpa' => {
'dad' => {
'child 1' => [] , 'child 2' => ["3","4"]
}, 'uncle' => {
'child 3' => [], 'child 4' => []
}
}
}
class TreeCustom < Tree
def visit_all(&block)
visit &block
if children.kind_of?(Array)
children.each {|value|
TreeCustom.new(value).visit_all &block
}
elsif children.kind_of?(Hash)
children.each {|key,value|
TreeCustom.new(key, value).visit_all &block
}
else
TreeCustom.new(value).visit &block
end
end
def visit(&block)
block.call self if self.node_name
end
end
ruby_tree2 = TreeCustom.new(false, quest.clone)
ruby_tree2.visit {|node| puts node.node_name}
ruby_tree2.visit_all {|node| puts node.node_name}
・grepを実装
if ARGV.length != 2
puts "wrong number of arguments #{ARGV}"
exit
end
word = ARGV[0]
filename = ARGV[1]
f = open(filename)
f.each_with_index {|line, key|print (key +1).to_s + ')' + line if line.index(word) != nil}
f.close
以下ブラウザ検索のメモ
irbでも補完
require "irb/completion"
組み込みコマンドのshell-modeを使うと、プロンプトにカレントディレクトリが表示され、tabキーでディレクトリ名を補完できるようになり、よりファイル操作が簡単になります。
Ruby には Perl に由来する while 修飾子と until 修飾子もあります。 修飾する式が begin…end か否かで 動作が異なるという非常にまぎらわしい意味を持ちます。 過去の遺産を引き継ぐとき以外,使わないのが無難です。 伝統的には C++/Java の do S while (E ); を模倣するために begin…end の特別ルール付きで使われることがありますが (そして,この模倣こそが特別ルールが導入された理由ですが), 前述のとおり loop イテレータと break で十分表現できます。
null/nil の扱いをオブジェクト指向的に考え直す
シンタックスとは
コンピュータ言語における構文規則。プログラミング言語、構文解析など参照。
範囲オブジェクトのクラス。範囲オブジェクトは範囲演算子 .. または ... によって生成されます。.. 演算子によって生成された範囲 オブジェクトは終端を含み、... 演算子によって生成された範囲オブジェ クトは終端を含みません。