ここで問題です。今までのコードを踏まえた上で、次のコードをProcオブジェクトを実行(
call
メソッド呼び出し)する形に書き換えてください。ただし、ブロックを使ってはいけません。xs = (1..10) xs.map{|it|it.to_s(2)} #=> ["1", "10", "11", "100", "101", "110", "111", "1000", "1001", "1010"]
とりあえず、同じ処理を Squeak Smalltalk で書くとこうなります。
| xs |
xs := (1 to: 10).
xs collect: [:it | it radix: 2]
"=> #('1' '10' '11' '100' '101' '110' '111' '1000' '1001' '1010') "
さて。Smalltalk では何でも(原則として)メッセージングなので、ここはいったん関数型の文脈から外れてメッセージングでの解決を試みてみましょう。
ここで問題なのは
[:it | it radix: 2]
というブロック内の
it radix: 2
という式を、ブロックを使わずに表現するにはどうしたらいいか?というところです。
ちなみに、Ruby での例と同様にcapitalized
のような単項メッセージであれば、Squeak Smalltalk でもシンボルで代替することができます。[^1]
[^1]: すべての Smalltalk で、というわけではありません。単項メッセージ式ブロックの代わりにその単項メッセージのセレクタシンボルを用いるというような置き換えが可能な細工がしてあるのは Squeak の他には Pharo のように、Squeak から派生した処理系など一部の処理系に限られます。
| xs |
xs := #(akechi kokoro itoh chika ayase ena koshimizu sachiko).
xs collect: [:it | it capitalized]
"=> #(#Akechi #Kokoro #Itoh #Chika #Ayase #Ena #Koshimizu #Sachiko) "
| xs |
xs := #(akechi kokoro itoh chika ayase ena koshimizu sachiko).
xs collect: #capitalized
"=> #(#Akechi #Kokoro #Itoh #Chika #Ayase #Ena #Koshimizu #Sachiko) "
もちろん、この方法は二項メッセージやキーワードメッセージなど引数をとる場合は使えません。
ところで、Smalltalk ではit radix: 2
という式は「it
にradix: 2
というメッセージを送る」と解釈されます。
そこで、引数を含むradix: 2
というメッセージをファーストクラスオブジェクトとして作ってやって、それをcollect:
の引数としてブロックやシンボルの代わりに渡してやればよさそうです。(本当か?)
| xs |
xs := (1 to: 10).
xs collect: (Message selector: #radix: argument: 2)
が、しかし、まあ、これは普通にエラーになります。←ぉぃ!
MessageNotUnderstood: Message>>value:
どうやらcollect:
の引数にはvalue: arg
というメッセージを送られるようなのですが(通常、collect:
は1引数のブロックを引数にとるので当たり前か!)、メッセージオブジェクトにはこのメッセージに対する振る舞い方がわからない、というわけですね。[^2]
[^2]: 本当はわかっていて、MessageNotUnderstood という例外を投げるという振る舞いをしているわけですが、まあそれはまた別の話。
しかたがないので、Message>>#value:
を定義してやります。もとい。Message
にメッセージを投げてそのように振る舞いを変えてもらいます。
Message compile: 'value: arg
^self sendTo: arg'
これでOKです。前に出てきたエラーを表示していたウインドウ(ノーティファイア)がまだ閉じられていなければ、それの「Proceed」ボタンを押すか、エラーを出していた元の式を再評価することで期待通りの結果が得られます。
=> #('1' '10' '11' '100' '101' '110' '111' '1000' '1001' '1010')
めでたし、めでたし。(ぉぃぉぃ…)