2008年3月30日日曜日

Ruby のイテレータ (2) – Enumerable と Comparable モジュール

Ruby のブロック付きメソッドとイテレータ - yield の様々な使い方」のつづき

1. 要素を保持する親クラスと、要素となる子クラス

080329-004次のような例を想定する。

  1. 「人」が「グループ」 に所属している。
  2. 「人」は `名前' と `年齢' を属性として持つ。

「グループ」クラスは親クラスで、「人」クラスは要素となる子クラス。

class Person
  attr_reader :name , :age
  def initialize(name,age)
    @name = name
    @age = age
  end
end

親クラスとなる「グループ」は、保持する「人」の集合に対して責務を持っており、「人」を「グループ」に追加する操作を持つとする。

class Group
  def initialize
    @persons = []
  end
  def add(person)
    @persons << person
    self
  end
end

 

2. Enumerable モジュールを親クラスにインクルード

「グループ」クラスには、「人」を追加する操作だけではなく、

  • 特定の「人」を抽出したり
  • 全ての人が、ある条件を満たすのか調べる

ようなメソッドも定義したい。 Ruby では、自分でそのような操作を実装しなくても、「グループ」に Enumerable モジュールをインクルードするだけで、便利なメソッドがいくつも追加される。

Enumerable モジュールを「グループ」にインクルードする方法は、

  1. 「グループ」クラス内に、include Enumerable と記述。
  2. 「グループ」に、「人」の集合の要素を順番に取り出す each メソッドを定義。

このような Enumerable モジュールの使い方を Mixin と呼ぶ。

each メソッドを定義する理由は、Enumerable - Rubyリファレンスマニュアル  によると、

(Enumerable クラスは) 繰り返しを行なうクラスのための Mix-in。このモジュールのメソッドは全て each を用いて定義されているので、インクルードするクラスには each が定義されていなければなりません。

 

each メソッドの実装方法

each メソッドの実装、要素を保持する親クラスから、要素をひとつづつ取り出し、その要素にブロック(関数)を適用すること。以下に、Group クラスの each メソッドの実装を示す。

class Group
  include Enumerable
  def each
    @persons.each do |person|
      yield person
    end
  end
end

each メソッドの中で、yield が使われている。この記述で、yield の呼び出しの際、「グループ」が保持している各々の person を、each メソッドに与えられるブロックに引き渡していることになる。

この書き方でわかりづらい点は、each メソッドの引数にブロックが与えられることが明示されていないこと。メソッドの中で、yield が使われてることで、メソッドにブロックが与えることを想定しているがわかる。

( cf. jutememo's gist: 1350439 — Gist )

 

each メソッドを利用してみる

以下の順に、実際に each メソッドを使ってみる。

  1. 「グループ」オブジェクトを生成し、
  2. 「人」オブジェクトを追加する。
  3. 「グループ」オブジェクトの each メソッドを呼出す。
aGroup = Group.new.
         add(Person.new("Tarou",21)).
         add(Person.new("Hanako",15)).
         add(Person.new("Jiro",15))
                                  

aGroup.each do |person|
  puts person.name
end

 

Enumerable モジュールに定義されている collect , sort を使ってみる

Enumerable を Mixin すると、Enumerable モジュールで定義されている collect, sort などのメソッドを呼出すことができる。この2つのメソッドを試しに使ってみる。

p aGroup.collect{|person| person.age + 10}

aGroup.sort{|a,b| a.age <=> b.age}.each do |person|
  print person.name, person.age, "\n"
end

上記において、sort メソッドの呼び出しのとき、ソートの方法をブロックで渡している。

Enumerable - Rubyリファレンスマニュアル によると、

sort {|a, b| ... } 全ての要素を昇順にソートした配列を生成して返します。 ブロックなしのときは <=> メソッドを要素に対して呼び、その結 果をもとにソートします。

ここでは、Person クラスにおいて、<=> を定義してないので、上記のように、要素を比較する方法を、ブロックを渡す必要があった。

 

3. オブジェクトを比較するクラスに Comparable モジュールをインクルード

Enumerable の Mixin の方法がわかったところで、今度は上記の sort メソッドで利用された、「人」を比較するためのメソッドを「人」クラスに追加してみる。「人」オブジェクトを比較可能にするには、Comparable モジュールを Person クラスに Mixin する。

一例として、「人」を比較するためルールを、以下のように決める。

  1. 「はじめに `年齢' で比較し、
  2. もし同じ年齢だったら、`名前' のアルファベット順で比較する」
class Person
  include Comparable
  attr_reader :name , :age
  def initialize(name,age)
    @name = name
    @age = age
  end
  def <=>(other)
    cmp = @age <=> other.age
    if cmp != 0
      return cmp
    else
      return @name <=> other.name
    end
  end
end

tarou = Person.new('Tarou',21)
jirou = Person.new('Jirou',15)
hanako = Person.new('Hanako',15)

p tarou > jirou
p tarou < jirou
p tarou == jirou

p jirou > hanako
p jirou < hanako
p jirou == hanako

Enumerable モジュールは、each メソッドを利用して、様々なメソッドが定義されている。Comparable モジュールでは、<=> を利用して、いくつかの操作が定義されている。

上記のように、Person に <=> を実装したので、Group に Mixin した Enumerable モジュールの sort メソッドを、ブロックなしで呼出せるようになった。

( cf. jutememo's gist: 1350439 — Gist )

 

4. モジュールは、Template Method パターンを使っている

このようなモジュールのインクルードの動作の仕組みは、「まつもと直伝 プログラミングのオキテ 第9回:ITpro」 に、次のように書かれている。

Rubyのクラス・ライブラリでTemplate Methodパターンを最も活用している部分は,EnumerableモジュールとComparableモジュールでしょう。...

Comparableモジュールは大小比較の基本となる「<=>」メソッドを用いて,各種比較演算を提供しています。「<=>」メソッドの仕様はレシーバと引数を比較して,レシーバの方が大きければ正の整数,等しければゼロ,小さければ負の整数を返すというものです。このメソッドを基礎にして, Comparableモジュールは「==」,「>」,「>=」,「<」,「<=」,「between?」の6つの比較演算を提供しています。

Ruby で書かれたデザインパターン (Template Method) の実装例を見たい場合は、以下を参照にすると良い。

前者は、Module を Mixin して、Template Method を実現しており、後者は、サブクラス化によって実現している。ただし、Mixin とは、

一般にTemplate Methodは継承とセットで語られますが,Enumerableのようにインクルードするだけで継承関係に関わりなく任意のクラスに機能を追加できるのは魅力的です。もっとも,Rubyのインクルードは一種の(制限された)多重継承なので,何の不思議もありませんが。

( cf. まつもと直伝 プログラミングのオキテ 第9回:ITpro )

 

5. Yield はどのように呼び出され、動作しているのか?

Enumerable モジュールは、C で実装されているらしい。

Nabble - [ruby-dev:32712] Re: Enumerable can't take multiple parameters によると、

たとえばEnumerable#collectをRubyで定義する時にどのように書くか、という問題です。現在は
module Enumerable
  def collect
    result = []
    self.each{|x| result.push(yield x)}
    result
  end
end 
と等価になるように定義しています。

先ほど Group クラスで定義した each メソッドを参照しながら、 Enumerable の collect メソッドを見てみる。頭が混乱してくる。。 パタッ(o_ _)o~†

以下のように collect メソッドの呼出しをイメージしてみる。

080330-001

うーん、ややこしい (@_@;)  どこが一番想像しにくいのだろうか?順に動作を追って考えることにした。

  1. Group クラスに Mixin した collect メソッドを、ブロック付きで呼出す。
  2. Enumerable モジュールの collect メソッドの中で、 Group メソッドで定義した each メソッドを呼出す。
  3. Group クラスに定義した each メソッドでは、Person 要素を一つずつ取り出し、each メソッドに渡されたブロックの処理を進める。

例えば、先ほどの実行例で考えると、先頭の要素 `Tarou' が取り出されたとき、渡されたブロックの引数を展開すると、次のような値にが与えられているとイメージする。

{|tarou| result.push (yield tarou)}

ここでややこしいのは、yield が呼ばれていること(4)。

展開すると、こんな感じになるだろうか。

{|tarou| tarou.age + 10}

動作がわかりにくので、上記二つをまとめると、

{|tarou| result.push (tarou.age + 10)}

これを Person の要素分だけ繰り返して、 結果を 配列 result に詰め込んでいく。

 

Enumerable が関知していること

上記のように、個々の動作を追っていくと、何がなんだかわからなくなる。むしろ、Enumerable というモジュールの機能レベルで理解をしていく方がいいかもしれない。

Enumerable とは、 動詞 enumerate (列挙する、数え上げる) に由来する。「数え上げる」とは、対象がどのようなものであっても、複数の要素に対して行う行為を指す。

collect という操作であるなら、

「要素に対して、何らかの操作した結果の、集合を返す」

役割を持つと考える。要素を取り出す仕事は each が行う。

collect の中で呼出されている、each メソッドに渡されるブロック変数 x は、

「 x の中身が何なのか自分は関知しない」

ということを表わしている。その何だかよくわからない任意のものを、自分が呼出されたときに、与えられたブロックに渡し、「何らかの処理」を行わせた結果を受け取る。「何らかの処理」については、 Enumerable 自身は関知しない。ただ、「何らかの処理」の結果を受け取って、配列に詰め込むだけの役割を持つ。

 

6. 他の言語との比較

Haskell の map 関数と比較

Haskell にも、Ruby の Enumerable モジュールの collect に相当する map 関数がある。

map 関数の定義を見てみと、

ふつうのHaskellプログラミング (p76) によると、

map::(a -> b) -> [a] -> [b]
map f []     = []
map f (x:xs) = f x : map f xs

なんとシンプルな。。 (@_@;)

対象が何であれ、

「要素に対して、関数を適用する」

ということが素直に示されている。この定義を理解しておいてから、 Ruby の Enumerable モジュールの collect メソッドを見ると、何となく同じような形に見えてくる。yield x という文が、要素 x に対して関数を適用していることに等しい。

Haskell が再帰によって、要素に関数を適用するというところと、 Ruby が each によって、個々の要素を取り出し、順にブロックを適用するというところが違うけれど。

 

Java との比較

自分の場合、プログラミングは、 Java から入ったので、 Ruby のモジュールを見たときは違和感があった。Java の視点から見ると、 interface が外面だけでなく、中身も持っている感じ。Ruby はモジュールがあるから、Java よりも抽象的な表現による、コーディング促進されるのだろうか?

Java でオブジェクトを比較する方法を実装する場合、

  1. インターフェイス Comparable の compareTo を実装することによって、オブジェクト同士が比較可能にする。
  2. Arrays.sort, Collections.sort を利用してソートする。
  3. ソートするときに、Comparator を実装した匿名クラスのオブジェクトを渡せば、ソートの方法を変更することができる。これは、Ruby でブロックつきで呼出しているようなものと考えればよい。

ただし、クロージャと匿名インナークラスとの違いについては、MF Bliki: Closure に指摘されている。、

if you're a Java programmer you probably think "I could do that with an anonymous inner class", a C#er would consider a delegate.These mechanisms are similar to closures, but there are two telling differences.(...)

その二点とは、

closures can refer to variables visible at the time they were defined ...

Languages that support closures allow you to define them with very little syntax.

Ruby のブロックと Proc」へつづく…

 

連想事項

2008年3月29日土曜日

Firefox で リンクの作成 - MakeLink から Build Link へ乗り換え

1. Menu Editor と相性が悪いので、Make Link を使うのをやめた

他人に自分が見ているサイトを教えたり、ブログで引用するとき、「タイトル」と「アドレス」の両方を伝えることは欠かせない。

Firefox のアドオン Make Link を使うと、この2つの情報をコンテキストメニューから一度に取得できる。カスタマイズも容易なので重宝していたが、一つ問題があった。それは、アドオンをたくさん入れると、コンテキストメニューの項目が増える。これにより、Make Link を選択するために、コンテキストメニューから項目を探す必要があり、それにストレスを感じる。

これに対して、Menu Editor を利用すると、コンテキストメニューに表示されう項目をカスタマイズできる。しかし、Make Link との相性が悪い。 Menu Editor によるカスタマイズは、自分にとって必須なので、Make Link を使うことを諦めた。

 

2. Build Link は操作がスムーズ

Greasemonkey スクリプトである Build Link は、Make Link と同じ機能を持っている。

080329-003Build Link は、見ているページ上で引用したいテキストを選択するとアイコンが表示され、マウスオーバーで形式を選んでコピーする。Make Link と違って、コンテキストメニューから選択する操作をする必要がない。一連の操作を流れるようにスムーズにできる。 ^^

コピーできる URL の形式として、tinyURL を選べるのも気がきいている。驚きだったのは、Make Link のようなカスタマイズも、簡単にできること。そこで、Build Likn に乗り換えることにした。

 

関連記事

2008年3月28日金曜日

Emacs で文字数を数える

  1. 文字数を数えたい範囲を選択
  2. M-x count-lines-regions

 

M-x how-many では正規表現に一致したものの数を数えることができる。

 

参考

本棚の整頓

デスクトップの整頓 に引き続き、今回は本棚の整頓。

 

現状の問題点

  • 本を読んだら、その場に放置する

これは、デスクトップが片付けられないことと類似した問題を孕んでいた。コンピュータの中と、現実な物理的なものの整頓。類似点もあれば、相違点もある。相違点として、一番大きいのは、当然ながら、物理的なものは場所をとるし、また、コンピュータと違って、検索にも時間がかかるということ。

「場所をとる」ということに関連して、「大きさがある」というのも問題。本によって、大きさが異なるという、この当り前の事実が障壁となる。こういうことを経験したことはないだろうか?本棚を効率的に利用としようとして、本棚の一区画の高さを経済的に設定した結果、本が大きすぎて、入れたい位置に配置できないということが。これは避けなければいけない。分類に例外を設けると、そこでワンクッション考えなくてはならないことが増える。ほんのささいなことだけれど、意外にストレスになる。

 

本棚の高さの単位化

080328-002これを解消するために、本棚の高さを単位化することにした。どのくらいの大きさにするかと言えば、

A4 の紙が縦に入る大きさ

である。この高さは、通常の本にとってみて、やや大き目のサイズ。しかし、この大きさにしておけば、大きさによって、例外的に別の場所に置かなくてはならないということがなくなる。このサイズで棚の高さを揃えていくと、本を置くには全く適さないサイズの段ができることがある。そういうときは、本以外の小物を置いておく場所として活用すればよい。

本棚を「資料を置く場所」という使い方をしている。普段書いているメモなどを、A4 の大きさのクリアフォルダに入れ、メモの内容と一致した、本の分類と同じ場所に置いておくことができる。関心のある事柄は、たいていそれに関する本を買っている。そのため、その近くに、思い付いたメモを入れておくと、メモ自体も活用しやすくなる。本棚は、本を置いておく場所ではなく、資料を活用する場所。本は、飾っておくためのものではなく、絶えず刺激を受け、考えるための材料である。

ちなみに、この方式は、知的生産の技術 に書かれていた、 

すべて一定の型のフォルダーにはさみこんで、それをふつうの本棚のような棚にたてるのである。 (p69)

に由来する。メモなどの資料は、上記の本では紙でできたフォルダを利用して整理していた。自分はクリアフォルダを使っている。コスト的な面と、中身が透けて見えるというメリットがあるからだ。また、クリアフォルダには、テプラでタイトルをつけておくと、綺麗で見やすくてよい。

 

分類基準の設定

収納する場所を確保したら、今度は分類基準について考える。この作業は、本を本棚に入れる行為とは、独立して行うのがよい。たいていの場合、分類を考えながら収納を行うと、「これをどこに入れようか?」と迷ってしまうことがある。その場合、最悪、多くの本を移動しなくてはならない事態となる。これでは非常に効率が悪い。だから、本を整頓する前に、メモを片手に、どのような本があるかチェックし、分類の設計を行う必要がある。調べてみると、いろいろな種類の本があることがわかる。予め、大雑把にグループ化しておき、どの棚にどの種類の本を置くか、特定の分類に属する本の量と相談して決めておく。最初にこれをやっておけば、本を収納する作業は、機械的に行うことができる。ちなみに、分類はあまり細かくすると、本を返すときに面倒になるので、ほどほどの分類にしておくのがコツ。必要なときに、ちょっと探すコストよりも、本を棚に戻せないことによる弊害の方が大きい。

分類ができない場合、「その他」の棚を利用する。分類に迷ったら、迷わずここにブチ込む。自分の関心は、絶えず変化していく。それに合わせて、「その他」から独立させ、分類を成長させていけばよい。「その他」というのは結構おもしろいところで、自分の関心の中でも、「薄い」ものがここに集約される。しかし、どこかひっかかるために、このような場所ができるのだろう。ここから生まれるアイディアを大切にするとよいかもしれない。

 

時系列の棚

080328-003上記までで、本を片付けることができた。さて、次は運用における問題。本の整頓の最初の問題に戻ると、「元に戻さない」ということだった。この理由として、「また、近いうちに読むから、そこに置いておこう」という心理が大きく影響している。いくら緩やかな分類基準を設定して、本棚に戻しやすくしても、この考えに抵抗するのは容易ではない。

そこで、それを逆手にとって、「近いうちにまた読む」であろう本を収納する、例外的なスペースを確保することにした。場所としては、本棚の中で一番手に取りやすい位置にある一区画を利用。

利用方法は、最近使った本は、一度この棚へ、「右から左へ、使った時間順に入れてしまう」ことだ。この区画だけ、最近読んだ本が分類に関係なく並ぶことになる。分類がぐちゃぐちゃでも、範囲が狭いので、探すのに迷うことがない。加えて、最近のものほど、左へ並んでくるので、アクセスが容易になる。この方法は、「超」整理法 に由来している。

棚の区画は、結構狭い。入れることができなくなったら、右側の方から、つまり、古いものを適当な数だけ、分類の棚に入れていく。

この「時系列の棚」というのが結構よかった。以前は、机の上に山積みにされていた本が、机を占拠し、作業スペースを侵食していたが、これによりポンポンと気軽に本を投げ込んで置くことができるようになった。机の上が片付くようになった。おかげで作業がしやすい。 ^^

Polipo を試した

インストール

以下のサイトを参考にして、インストール。

起動時に polipo が起動するように、上記で紹介されていた tolipo.exe をスタートアップフォルダに入れた。

設定

設定ファイル polipo.conf は、Polipoの設定とチューニング を参考にした。

dnsNameServer に設定する値は、コマンドラインから nslookup で表示される値。

Firefox のアドオンでプロキシの切り替え

Polipo を使うときと、直接接続するときの設定を簡単に切替えるために、SwitchProxy Tool インストールした。

邪魔にならないように、表示 > ツールバー > カスタマイズ で、SwitchProxy のボタンを追加。

080328-001

Polipo の確認

http://127.0.0.1:8123/polipo/status?

また、Dolipo / polipo が効いているかどうかの確認の仕方 - shckorの日記 も参考に。

結果

Google Reader の読み込みが少し早くなった。

追記(2008.4.23): cache フォルダを D:\polipo\cache に移した。MOONGIFT: » Windowsでもリンク機能を「NTFS Link Ext」 で紹介されていた NTFS Link Ext を使って、ジャンクションを作成し対応した。

Ruby のブロック付きメソッドとイテレータ - yield の様々な使い方

1. 要素を取り出す each メソッド

Ruby の「イテレータ」は、複数の要素を持つオブジェクトが、個々の要素を取り出し、何らかの処理を適用するときに使うと便利。

一番基本となるメソッドが each 。例えば、Array クラスの場合、each メソッドで、要素をひとつづづ取り出すことができる。

[1,2,3,4,5].each do |i|
  puts i
end

これはどういう仕組みで、このように書けるのだろうか?

 

2. イテレータの役割

オブジェクト指向スクリプト言語 Ruby」(p94) では、イテレータについて、次のように述べられている。

イテレータ (Iterator) はメソッドの一種で、もともとは繰り返しの抽象化のためのものでした。

しかし、はじめから 「繰り返しの抽象化のため」 という視点で、イテレータを理解しようとすると、わかりずらい。「繰り返しの処理のため」にあるというよりは、

関数 (処理) をメソッドに渡すための仕組み

と理解しておく方がよい。

 

3. yield の意味

イテレータに関して、最初に覚えておく単語は、

yield

これは、渡された関数に処理を移すための命令。もっと端的言うなら、yield が書かれたメソッドに渡されたブロックを、実行するための手段。Ruby では、関数と言わずに 「ブロック」 と呼ぶので、以降ブロックと呼ぶ。

ちなみに、Yahoo!辞書 - yield を調べると、その中の 1 つの意味として、

3 [III[名]([副])] …を放棄する, 手放す, (…に)明け渡す((up/to ...)); …

((~ -self))(誘惑などに)身を任せる, ふける((to ...));

[V[名](as)[名]] 身を任せて(…に)なる...

They yielded (up) the city [=the city (up)] to the enemy.

町を敵の手にゆだねた

Ruby の yield に当てはめて意味を考えると、

渡されたブロックに処理を「明け渡す、身を任せる」

と言った意味として捉えておけばいいかな。

 

4. 引数の数を変えてyield を呼び出してみる

引数なしで yield を呼び出す

渡されたブロックを処理する関数 test を定義してみる。

def test
  yield
end

test{puts "hoge"}

test を呼出すと、呼出したときに渡したブロックが yield によって呼出される。

 

yield に引数を1つ渡す

yield に引数を与えると、yield が書かれたメソッドに渡されたブロックの、ブロック変数に引数が渡される。

ブロック変数とは、ブロックの先頭で

|変数|

と記述されている変数のこと。

def test2
  yield "hoge"
end

test2{|x| puts x}

 

yield に複数の引数を渡す

yield に引数を複数渡すと、それに対応したブロック変数に渡される。

def test3
  yield "hoge", 100
end

test3{|x, y| print x, y, "\n"}

 

5. block_given? メソッドで、ブロックのある・なしに対応

これまでは、メソッドに必ずブロックがある場合を試した。これを、ブロックが渡される場合と、渡されない場合に対応できるメソッドに変更する。

def test4
  if block_given?
   yield
  else
   puts "no blcock"
  end
end

test4{puts "hoge"}
test4

 

6. 要素を取り出す、イテレータとして用いる yield

yield を複数回呼び出す

yield は、渡されたブロックを実行するための手段であることが実感できた。

次は、「要素を走査するイテレータ」の使い方を、yield を用いて書く。

def test5
  for i in [1,2,3]
   yield
  end
end

test5{puts "hoge"}

for ループにより、yield が 3 回実行されている。これにより、渡したブロックが 3 回される。

 

yield を複数回呼び出すとき、引数を一つ渡す

上記を少しだけ変更する。 yield を呼出す際、for ループで使われている変数 i の値を渡す。

def test6
  for i in [1,2,3]
   yield i
  end
end

test6{|x| puts x}

これにより、先ほどと同じく、渡されたブロックが 3 回実行されるが、その度にブロック変数に渡される値が異なる。

 

yield を複数回呼び出すとき、引数を複数渡す

yield を複数回呼び出す。今度は値を複数渡してみる。

def test7
  for i in [1,2,3]
   yield i, "hoge"
  end
end

test7{|x,y| print  x, y, "\n"}

 

7. 「引数」と「ブロック」を受け取るメソッドの定義

引数を受け取るメソッドを定義する。ただし、ブロックも受け取る。

以下のメソッドでは、引数の値に応じて、ブロックの呼出しを変化させている。

def test8(val)
  for i in [1,2,3,4,5]
   yield i, "hoge"  if i > val
  end
end

test8(0){|x,y| print x, y, "\n"}
test8(2){|x,y| print x, y, "\n"}

このように、Ruby では、直接関数を渡すのではなく、「ブロック」を利用するところに特徴がある。慣れないと、素直に関数を渡せた方がシンプルでいいのになと感じる。 ^^;

Ruby のイテレータ (2) – Enumerable と Comparable モジュール」へつづく…

2008年3月26日水曜日

配列を「集計」するときの手順のわかりにくさ

1. 配列の要素を集計をするときに感じた違和感

配列の要素を集計をすることを考える。

例えば、1 ~ 5 までの整数に対して、

1 + 2 + 3 + 4 + 5

の答えを求める場合、次のような手順を踏む。

Ruby で書くなら、

ary = [1, 2, 3, 4, 5]

total = 0
for elem in ary
  total += elem
end

puts total

もちろん、慣れているので、この計算の方法に抵抗は感じない。

しかし、この手順を初めて見たとき、

「わかりにくい」

と感じた。極めてシンプルなコードなんだけれど、どこか頭が混乱するような、そんな感覚に陥ったことを覚えている。

では、その原因はどこにあったのだろうか?

 

2. わかりにくい理由は、「要素の走査」「計算」「変数の再代入」を行なっているから

頭が混乱する印象を受けたのは、以下の箇所。

total += elem

コードの意味を、わかりやすくするために、書きなおす。

total = total + elem

全体のコードで行なっていることは、

  1. for によって要素を走査し、
  2. その途中で計算を行う。

気になるのは、total の使い方。 配列を走査している最中に、

  1. 集計するための total から値を取り出し、
  2. それを計算の後、再び total へ設定する。

つまり、以下の 3 つの要素が絡み合っているため、何をやっているのか想像しにくい。

  • 要素の走査
  • 計算
  • 変数の再代入

 

3. 最初は集計の方法をイディオムとして覚えた

プログラミングを始めた当初は、厳密にどのように動いているかというよりも、

このようなイディオムによって集計を行うんだ

と、感覚的な理解をしていた。

今では、配列の要素を「集計」しようと考えたとき、自然と上記のようなコードを書く。しかし、これがどのように動くかを、頭の中で全て思い描けるかと言えば、実はあやしい。デバッガを動かし、それぞれの変数の動きを目で追い、「なるほどなぁ」と思う。それでもコードを見ると、だまされたような感覚に陥る。

ところで、自分の頭の容量は小さい。同時に色々なことを覚えておくことも、把握しておくこともできない。将棋の棋士は、同時に何手先も読むと言うが、あれはいったいどういう頭の仕組みをしているのだろうか。だから、自分の「集計」に対する理解は、まるで刺激に対する反応するようなものだと感じる。これが要求されたら、この方法をとる。まるで、条件付けされているパブロフの犬のようだ。

 

4. 計算の様子をイメージすると、わかりにくい理由がより明確になる

集計をするコードに戻る。

変数 total が、全体を理解する上で、やっかいな存在。 最初に変数が宣言されているのが、for ループの外にある。つまり、要素を走査することとは、別の文脈に存在する。それが要素を走査している文脈に絡んでくるからわかりにくい。

「いつ、どこで、何をしているのか?」

が把握しにくい。

特に、total に elem の値を加算した後、自分自身に再代入しているので、

「誰がどうなったの?」

って感じる。 (@_@;)

イメージしにくいので、絵を描いてみる。そうするば、見通しが立てやすくなる。

080326-001

  1. 配列の要素を elem に割当てる。
  2. total と elem を加算する。
  3. 上記の結果を total に割当てる。

1 ~ 3 を要素ごとに繰り返す。

絵を描いてみると、「加算」を行っている文脈と、 total が存在する文脈が異なっていることがはっきりする。しかし、コード上では、

total = total + elem

のように、一文で簡潔に表現しされている。

この点が、自分のように容量の小さい頭には、イメージするのが難しい所。複数の文脈が一箇所に集約されていることが混乱の元になっている。

 

5. 計算の手順を分離し、各々役割をクラスに与える

では、これを理解しやすくするには、どうすればいいのだろう?

「要素の走査」「計算」「変数の再代入」を、次のように二つに分けて考えることにした。

  • 「要素の走査」
  • 「計算」「変数の再代入」

下図のようなイメージした。

080326-002

集計をするための Total クラスを作り、集計をするための役割を与えた。つまり、「計算」「変数の再代入」の操作を Total クラスにカプセル化。 (まぁ、普通こんなことはしないけれど ^^;)

# 集計の値を保持するクラス
class Total   attr_reader :value  # 集計の値   # 初期化   def initialize    @value = 0   end   # 集計の値に val を加算   def add(val)    @value += val   end
end

add メソッドの中身を見ると、「与えられた値を、これまでの値に加算する」という、極めてシンプルな役割を持っていることがわかる。

このクラス使うには、以下のようにする。

ary = [1, 2, 3, 4, 5, 6]

total = Total.new
for elem in ary
  total.add(elem)
end

puts total.value

for ループの中身を見ると、要素を走査し、Total に「要素の値を追加してね☆」とお願いしているだけになる。

繰り返すが、普通こんなコードは書かない。ただし、自分のようにワーキングメモリの小さい脳みそにとって、このような表現の方が、動作の理解はしやすいと感じる。

 

6. Enumerable の inject を使う場合

ところで、Ruby を使っているなら、イテレータを使って、次のように書くことができる。

total = 0
[1, 2, 3, 4, 5, 6].each do |elem|
  total += elem
end
puts total

Enumerable の inject メソッドを使えば、より簡潔に、

puts [1, 2, 3, 4, 5, 6].inject{|result, item| result + item}
ただし、シンプルだけど、動作をイメージしにくい。

Enumerable - Rubyリファレンスマニュアル によると、

inject([init]) {|result, item| ... }

最初に初期値 initself の最初の要素を引数にブロックを実行します。2 回目以降のループでは、前のブロックの実行結果と self の次の要素を引数に順次ブロックを実行します。そうして最後の要素まで繰り返し、最後のブロックの実行結果を返します。 ...

初期値 init を省略した場合は、最初に先頭の要素と 2 番目の要素をブロックに渡します。この場合、要素が 1 つしかなければブロックを実行せずに最初の要素を返します。要素が空なら nil を返します。

inject の意味は、Yahoo!辞書 - inject によると、

1 …を(…に)注入する((into ...));…に(…を)注入[導入]する, 入れる((with ...))

inject a tank with water [=inject water into a tank] タンクに水を注ぎ入れる

ブロックで実行した結果を、再注入するという意味合いなのだろうか?

あぁ~、それにしても動作を想像しにくい。 パタッ(o_ _)o~†

とりあえず、絵に描いておこう。

080326-001

  1. 先頭から 2 つ要素を取り出し、ブロック変数へ入れる。
  2. ブロックで実行した結果と、次に要素を取り出し、ブロック変数へ入れる。

これを末尾まで繰り返す。

 

7. 「再帰」で集計するには

for ループを使った計算は、再帰的な定義で置き換えることができる。

ary = [1, 2, 3, 4, 5, 6]

def total(ary)
  return ary[0] if ary.size == 1
  return ary[0] + total(ary[1..ary.size-1])
end

puts total(ary)

これは、次のように集計の手順を考えていると言える。

合計 = 要素の先頭 + 2 番目以降の要素の合計

要素が一つしかない場合は、当然、次のようになる。

合計 = 要素の先頭

イメージとしては、

080326-002

「先頭と、それ以降、という構造」が、リストの至るところで見られると見なし、順次関数を適用していく方法。

この方法では、「要素の走査」という部分が、「再帰的な関数の適用」にすりかわり、「変数の再代入」が消失し、「計算」のみが残っている。しかし、これが直観的にわかりやすいかどうかと問われたら、微妙。 ^^;

慣れの問題なのかな?

2008年3月25日火曜日

サクラエディタ で Ruby - コードの色付けと、プログラムの実行

1. サクラエディタ本体をダウンロードする

サクラエディタを使い、Ruby のコードを書きたい。予め、

より、サクラエディタをダウンロードして、インストールしておく。

 

2. コードの色付け

次に、サクラエディタで Ruby のコードを書いたときに、予約語を色付けしたい。そのために、

より、RubyDef.lzh をダウンロードする。

ダウンロードしたファイルを解凍し、readme.txt の「使い方」に従う。

ただし、readme.txt 中の「タイプ別設定」 をするとき、事前に「タイプ別設定一覧」で未設定のものを選択しておくこと。

デフォルトの設定では、行の間隔が狭いように感じたので、

  • メニューより、「設定 > タイプ別設定

の「行の間隔」を「2」ドットに設定した。

 

3. プログラムの実行

Ruby のコードを実行するには、

  • メニューより、ツール > 外部コマンドの実行

名前のフィールドには、

ruby "$F"

と入力する。これにより、現在編集中のファイルが実行される。

ただし、$F をダブルクォーテーションで囲むことに注意すること。

 

参考

Emacs で特定範囲をコマンドで実行する

1. プログラムの実行

Emacs 上で書いたプログラムを実行するには、

M-!

で Shell Command を呼び出し、プログラムを記述したファイルを指定する。

例えば、以下の ruby のプログラムを実行するには、

[1, 2, 3, 4, 5].reverse_each do |item|
  puts item
end

M-! を入力した後、「ruby プログラム名 RET」。

 

2. ファイル上の一部のコードを実行する

ファイル上で、いくつかの小さなプログラムを試している場合、特定の部分だけ実行して、結果を得たいことがある。このとき、実行したい部分の範囲を選択し、

M-|

を入力する。上記の場合では、 「ruby RET」 で実行される。 

先ほどの M-! で実行した結果は、別のフレームに表示される。複数の小さなプログラムを試していると、ファイルの最後の方に書いたプログラムの結果を見るとき、わざわざスクロールさせないといけない。

追記(2008.3.27) : プログラム実行後は、リージョンが解除されてしまう。 再度実行したい場合は、 C-x C-x で、ポイント(カーソルのある位置) とマーク (リージョンの開始位置) を入れ換えるコマンドを実行すると、すぐに範囲選択ができる。 

また、マークをした後に、C-sC-r による検索で範囲を選択するのもよい。

訂正(2008.6.15) : コマンド実行後も、リージョンは記憶されているので、範囲が選択されてないように見えても、M-| ですぐに実行できる。

 

参考

2008年3月24日月曜日

デスクトップの整頓

ぐちゃぐちゃなデスクトップ

もう 10年以上も前のことになるが、はじめて Mac を触ったとき、「デスクトップ」って何だろ (?_?) と思った記憶がある。ここにいったい何を置けばいいのだろうか?よく聞いたのは、

「作業中のファイルを置いておく場所」

ということ。はじめは、よく使うアプリケーションのエイリアス (Windows でいうショートカットのこと) を作成し、ランチャー変わりに使っていた。また、ダウンロードしたものを一時的に置いたり、試しに作ったファイルをとりあえず置いたりもした。結果、いつもデスクトップはぐちゃぐちゃ。。。(@_@;) どこに何が置いてあるのかわからなくなってしまった。

「とりあえず」な誘惑

080320-006この「とりあえず」という言葉がいけない。心の中では、

「後でちゃんと片付けよう!」

と考えているのだけれど、結局いつまで経っても、その「」は来ない。(o_ _)o~† 段々嫌になってくると、ゴミ箱ではなくて、「ごみ袋」という名前のフォルダを作成して、全部一気にそこの放り込み、必要なもをそこから取り出すということを何度も繰り返していた。ゴミ箱には捨てることができない、このイサギの悪さ。実質、ゴミ箱なのに「ゴミ袋」。「ごみ袋」に入れていることにより、なくならないという安心感と、デスクトップがスッキリしたという解放感に一時爽快を覚え、何の問題解決にもなっていないことを忘れることができた。

 

ぐちゃぐちゃな理由

性格と習慣の問題

さて、あれから 10年以上の年月が経過しているが、今自分のデスクトップはどうであろうか?はい、もちろん、ぐちゃぐちゃです ^^; 結局、デスクトップというメタファーを全く有効に利用できていない。進歩なし。パソコンがいくら性能がよくなっていても、結局、運用が変わらなくては、同じような問題は繰り返される。

なぜ、デスクトップがぐちゃぐちゃになってしまうのだろうか?理由を考えてみた。まず、根本的なところ。

  • 整理・整頓の習慣がない。

これは言わずもがな。そもそも性格的にズボラで、几帳面ではない。 (変なところで神経質ではあるが。^^;) 世の中には、潔癖症で、常に身の周りを綺麗にしていないと落着かないという人もいるようだが、全くあてはまらない。パソコンのデスクトップならぬ、実際の机の上も、同様にいつもぐちゃぐちゃ。作業効率の高い人の中には、一件乱雑なように見える机でも、実は検索にとって効率的に配置されているという話も聞くが、自分の場合は違う。ものすごく検索効率は落ちているし、作業がしにくい。では片付ければいいじゃん!という話だが、これまた、そう簡単にできるものではない。 「ここに置いておかないと、続きができない」という感覚に捕われてしまうからだ。

一時的なはずなのに...

ちなみに、机の上だけではなく、部屋の中も同様にぐちゃぐちゃ。読みかけの本が散乱している。パソコンのデスクトップがぐちゃぐちゃな理由と、部屋が乱雑であるのは、同じ理由のような気がしてくる。そう、それは、場所を個々の作業場の「しおり」とし、作業状態を明確に管理していないのである。では、ちゃんと作業状態を管理すればいいと思うのだが、それができない。面倒だからという理由が一番大きい。

何が面倒なのだろうか?思うに、管理するコストが高いと考えてしまうからだ。例えば、興味のある事柄に関する本を数冊読んでいたとする。そうすると、そこから別の本を読みたくなってしまうのが常。最初から最後まで通して読むのならいいのだけれど、たいてい途中で興味を失い、また読みたくなるのを待つことが多い。で、そのとき、わざわざ本棚に戻すことをしない。戻してしまったら、二度と読まない気がするからだ。だから、その場に放置する。そして、放置された本で部屋が埋めつくされ、作業場が圧迫される。これをスッキリさせるには、どうしたらいいか... あれを読んで、これを読んでという履歴をどこかに書いておくのがいいのだろうか?でも、それは面倒だ。

結局、これはどういう問題かと言うと、

一時的だと思って試したものを放置し、新たに別の作業をはじめる。

「一時的に...」と思っているのだけれど、結局、その場で半永久的に留まっている。埃がかぶっているのにもかかわらず、それを見ると、

「近々手をつけるから、そこに置いておこう」

と思ってしまう。毎回思う。「あぁ、見てしまった。見なければ、片付けられたのに...」と矛盾することを考える。

分類できない

更にもう一つ問題が。それは、

散らかした物を分類できない

散らかっている状態。そこには、散らかしたときの文脈がある。あれを読んで、これを読んで... あれをやって、これをやって。そこには目に見えないつながりがある。散らかされ方に重要な情報の痕跡がある。これを保存しておきたいと、つい考えてしまう。分類して元に戻すとき、そういった文脈を分解せざる終えないことがある。それでは、自分にとって大事だと思う情報が失われてしまう。物事は、一気に解決できない。だから、そのとき作業している状態がそのまま再現されていた方が、後で同じ問題を解決しようとするとき都合が良い。だから、余計に片付けられない。

 

対策を考える

さて、どうしたものか... ^^;

習慣付けること。これが多分一番難しい。できる人なら、何も自分のように困ることはない。自分としては、GTD を使い、「整頓する」という項目を作り、定期的に実施したいところ...

ところで、 GTD で一番自分にとって難しいと思うのが、定期的なレビュー。なぜかできない。やると絶対に良いはずだと思っていているのだけれど、できていない。習慣化されていない。

なぜ、定期的なレビューをしないのだろうか?レビューしようとするとき、何をしているのだ自分よ?考えてみると、目新しい情報に目移りし、新なタスクをはじめている。やりかけのものは、放置され、別の関心にエネルギーがシフトしてしまっている。どこか、デスクトップがぐちゃぐちゃになる理由に似ている。一時的なやりかけのものを放置し、別のことをしてしまう...

では、なぜ目移りするのだろうか?それは、それまでやっていたこと、調べていたことが行きずまり、そこで達成感を得られない状態になっていることが根底にある。この状態が続いていると、非常にストレスフル。思うような結果がなかなか得られないからだ。そこで、それを代償するために、新しいことをはじめ、達成感を得ようとする。一番お手軽なのは、未知の事柄について興味を広げること。情報のインプットに始終すること。新しい情報を読むのは楽しいし、何よりもあまり考えなくていいから、楽。惰性で読める。新しい事柄を読めば、そこから派生して更に新しい事柄を調べたくなる。こうして、古い事柄、やりかけのものは奥の方の地層に埋もれてしまう。

これをどうにかするには、新しい事柄に目移りするを意識的にやめるようにしなければならない。情報のシャットアウト。興味を拡散させない時間。そういう期間が必要だ。ぐっと我慢。今、目の前のものを、とりあえず、片付ければ、それはそれでストレスか開放されることを体に覚え込ませなければならない。

大雑把に分類する

「楽で楽しい」と感じることは習慣化される。とすると、整頓が楽で楽しいと感じるものになればいいはずだ。整頓できない最大の理由は、うまく分類できないことによる。分類は、厳密に分類しようとすればするほど、それがストレスとなる。だから、「ほどほどに分類する」ことを心掛けることにする。それが何であるか、どこに分類されるかは、あまり悩まない。どこにいったかわからなくなったら、また探せばいいくらに考えておく。

マイドキュメントの整理については、部類しないでどんどん放り込むということを実践している。しかし、これでも、デスクトップは汚れていく。なぜか?

  1. 試したアプリを放置。
  2. マイドキュメントの整理を徹底していない。

「いつかやる」という名前のフォルダ新し物好きで、何か便利そうなものがあると、とりあえずダウンロードして試してみたくなる。そのため、デスクトップは圧縮ファイルと、その解凍したもので氾濫する。常時使うと決めたもの関しては、ちゃんと整理している。そうでないものが問題だ。今後、使うかどうかわからない微妙なものが困る。 Program Files に入れるわけにもいかず、デスクトップに放置。ゴミ箱に入れてしまったら、二度とそのアプリを探せなくなるかもしれないという危惧があるからだ。

「よし!これに GTD を適用しよう」と考えた。そこで、こんな名前のフォルダをデスクトップに作った。「いつかやる」 ^^;

「本当にやるのか?」という思いもあるけれど、デスクトップを綺麗にするという目的には叶っている。

080324-014さて、全部、ここにブチ込んでみた。いや~スッキリデスクトップ!しかし、まだ残っているものがあった。それは、マイドキュメントに入れるにも入られない微妙な資料。調べてみると、これには種類があることがわかった。それは、「いつかやる」に入れておいて問題のないものと、「近々考えたい」というものだ。そこで、これに対して 「近々やる」というフォルダを作成した。

これでとりあえず、デスクトップ上はスッキリし、作業場としての機能が回復した。必要でないものが置いてないデスクトップの心地良さ。この気分をしっかりと覚えておくことにしよう。汚れたら、整理したくなるように。 ^^;

 

関連記事

エクスプローラはもういらない? - UltraExplorer

Windows 標準のエクスプローラでは、ファイル操作において、物足りないと感じることがある。そんなエクスプローラを補完するために、いくつものファイラーが存在するが、UltraExplorer はその中でも痒いところに手が届く優れたファイラだ。

日本語化

Tools > Language > 日本語 を選択する。

設定

各フォルダごとに、自分が設定した表示方式を記録させるようにした。

  1. ツール > オプション
  2. Listview > 一般 の「フォルダ毎の表示を保存」をチェック。

080324-003

グループ化

マイドキュメントは、時系列でグループ化して表示されるようにした。(cf. マイドキュメントの整理法 - グループ化と HandySelector を使って整理なし)

リスト操作バーにある「グループ」ボタンを押す。

グループ化の方式は、「更新日時」を選ぶ。

20080324ultra1

おもしろいのは、上記の写真にある一番下の段「分類の基準の編集...」。これにより、グループ化の基準を細かく設定できること。

080324-009

フィルタ

Ctrl + F で「クイックフィルター」が表示される。「自動ワイルドカード」にチェックを入れておくと、検索したい語が、ファイル名の途中にあっても抽出される。

追記 (2009.1.20) : クイックフィルタを解除するには「クリア」ボタンを押す必要がある。マウスを使ってクリックしなくてはいけないので面倒だなぁと思っていたけれど、Ctr + F でクイックフィルタのフィールドに移動して、 Backspace で削除すればフィルタが解除されることに今更ながら気がついた。^^;

更に、クイックフィルターによって抽出されたフォルダに含まれるファイル対象に検索を絞り込みたいときは、 対象のフォルダを選択した後に、ファイル > FlattenFolder

080324-005

これにより、対象のフォルダ内が展開される。再度、クイックフィルターを利用するとよい。

履歴

複数のフォルダを対象に作業していると、使いたいフォルダに素早くアクセスすることができることが重要になる。表示 > ウィンドウ > 履歴ウィンドウ によって、操作していた対象のフォルダの一覧が得られるので、表示しておくと便利。

縦列モード

表示 > 縦列モード は、MacOSX のカラム表示のようにできるのでイイ。 ^^

コマンドライン

表示 > ウィンドウ > コマンドライン ウィンドウ によって、コマンドラインを表示できる。

表示 > ツールバー > リスト編集バー の表示によって、現在表示しているフォルダに移動できる同期コマンドボタンが表示されるので便利。

080324-011

エクスプローラとの連携

ツール > シェル拡張 > コンテキストメニュー拡張をインストール を選択すると、エクスプーラーの右クリックで、Open in UltraExplorer が表示されるようになる。

080324-012

追記(2008.4.18):隠しフォルダを表示させるには、オプション > General > ファイルオブジェクト の「隠し属性」をチェックする。

2008年3月23日日曜日

ST20G5 の BIOS アップデートに挫折 (ノω・、) ウゥ・・・

自作 PC というのはしたことがない。プラモデルよりも簡単と言うけれど、プラモデルと比べてパーツが高いぃ~ (@_@;) だから、手を出さない。いや、出せない。 ^^; パーツ同士の相性やら、あれにはこれがいいとか調べるのも面倒。そもそも、パソコンは Mac から入ったので、箱の中をいじるという思想がない。中が何であろうと、使えればいいじゃんと思う派。しかし、内心、全部自分でパーツを集めて組めたら、楽しいだろうなと思ってる。パワーアップしたければ、一部だけを変えるというのも合理的。

そこで、Mac から Windows に移り、デスクトップマシンを購入するとき、いざとなったら、CPU くら交換できるものにしようと考えた。自作はしたいけど、知識も経験もないので、怖くてできない。そこで、Shuttle のできあいのものを購入することにした。 ^^;

CPU は AMD Athlon 64 3200+ 。メモリは、1.5 GB。

 

BIOS をアップデートしたい...

購入してから、時間が経ち、最近、CPU のパワー不足を感じるようになってきた。 特に、スカイプのビデオチャットをしながら、他のことをしようと思うと、他のアプリのもっさり感は否めない。ストレスを感じるほどだ。これを何とかしたい。

筐体は、ST20G5 . サポートしている CPU のリストを見ると、AMD Athlon 64 X2 Socket 939 4800+ に変更できそうだ。しかし、どうやら、CPU を変更するには、 BIOS のバージョンを上げる必要があるみたい。

 

Winflash を使いたいのだけれど...

BIOS を変更するのに参考したサイトは、Winflashユーティリティの使用方法 。これに従い、WinFlash を利用して、BIOS をアップデートしようとした。まずは、Shuttle の Download の Utilities から、 WinFlash をダウンロード。これを使って、BIOS のアップデートを試みた。しかし、現在の BIOS を保存することはできたが、アップデートしようする 対象の BIOS を開こうとすると以下のようなエラーが表示された。

080323-004

"Please load the correct BIOS file!"

本家から何度もダウンロードしているのに、なぜかダメ。 (@_@;)

同じような症状の人はいないかと探してみたら、価格.com - シャトル ST20G5 クチコミ 『パケット送信の異常で困っています』 に、

アップデートオプションに全部チェックを入れ、CMOSオプションのCMOS初期設定にチェックを入れて実行するとうまく行きましたよ。

これを試してみたけれど、できなかった。

また、同スレには、以下のようにも書かれていた。

最新のft20s017を導入しようとしましたが、
Please load the correct bios
で、はねられてしましましたが、
ft20s00w → ft20s00z → ft20s013 → ft20s015
→ ft20s017
のように順番にUPしていったらできました

まず、今使っている BIOS のバージョンを確認することに。(How to identify model information, serial number, and BIOS version of XPC ? を参考) パソコンを再起動して、Tab キーを押して確認。 FT20SS14 だった。

ftp://ftp.shuttle.com/BIOS/st20g5/ の一覧 から、全てのバージョンの BIOS をダウンロードして、一つ一つ試してみた。しかし、相変わらず、上記のエラーメッセージが出るだけだった。

結局挫折した。 パタッ(o_ _)o~†

 

その他

他に、Awdflash を使って、フロッピーから起動して、BIOS をアップデートするようなことが書かれているのを見た。しかし、このパソコン、フロッピーない! パタッ(o_ _)o~†

未だにフロッピーディスクドライブって、何で売っているのだろうと思っていたけれど、こういうときに使うのかな?自作するときは、FDD を搭載するのは、常識なんだろうか。。。(@_@;)

うーむ、全く知識がないからわからない。難しい。。。

パタッ(o_ _)o~†

Firefox で Gmail の検索にスマートキーワードをつける

Gmail において、適当に単語を検索する。

ブラウザのアドレスが以下のようになっていることを確認したら、ブックマークをする。

http://mail.google.com/mail/?tab=om#search/検索した単語

Firefox で、ブックマークサイドバーを開き、今ブックマークしたもののプロパティを開く。

URL において、"検索した単語" の部分を %s で置き換える。

080323-003

キーワードを適当に付ける。

関連記事

2008年3月20日木曜日

Windows でファイル・フォルダを削除・移動できない - Unlocker でロックしているプロセスを特定し、ロックを解除する

1. ファイルやフォルダを削除・移動できない

ファイルを削除できない

Windows 上であるファイルを削除しようとしたら、

「ロックされてます」

とメッセージが表示された。しかし、削除したいファイルを使用しているアプリケーションが分からない。(@_@;)

 

フォルダを移動できない

あるフォルダを移動しようとしたら、次のエラーメッセージが表示され、移動できなかった。

別のプログラムがフォルダーまたはファイルを開いているので、操作を完了できません。

フォルダーまたはファイルを閉じてから再実行してください。…

SnapCrab__2012-7-25_16-5-56_No-00_th

 

2. Unlocker でロックを外す

SnapCrab_No-1360このような場合、Unlocker を使うと

  1. ファイルをロックしているアプリケーションを特定でき、
  2. ロックを解除できる。

 

インストール

インストーラーで Unlocker をインスールするとき、Delta Toolbar は必要なかったので、インストールしなかった。

SnapCrab_No-1356

 

ロックの解除と削除・移動

080320-004ロックされているファイルまたはフォルダをを右クリックして、

  • Unlocker

を選択する。

ロックしているプロセスが表示されるので、「全ロック解除」ボタンを押す。

SnapCrab_Unlocker 191_2012-7-25_16-7-50_No-00

これにより、ロックされていた対象を、削除または移動できるようになる。

ロックの解除と同時に対象を削除したい場合、左下のセレクトボックスで「削除」を選択しておく。

080320-003

Firefox で Google ノートブックの検索に スマートキーワード を設定する

Web サイトを見ていて、内容の一部を保存したいときは、Google ノートブックを使っている。保存したときにレイアウトが崩れてしまうこともあるけれど、Web ページをそのまま保存することが目的ではなく、メモして、後で活用することが目的なので、今のところ必要にして十分。

Web サイトをメモするだけではなく、思ったことをちょっとメモしておくにも便利。なぜなら、すべてのメモに対して、検索をかけれるから。メモがローカルではなく、Web 側にあるのもイイ。パソコンがクラッシュしても、メモが残っているという安心感が得られる。まぁ、Google のサービスをどこまで信用するかは、賭けみたいな要素があると思うけれど、少くとも、自分のパソコンがクラッシュするよりは、信用できる気がする。 ^^;

そんななくてはならない Google ノートブック。素早く検索するために、スマートキーワードを設定したい。しかし、「検索するためのフィールドで、右クリック > この検索にキーワードを設定」をしようと思ったら、表示されない!(@_@;) うーん、この検索窓、 JavaScript で生成しているのかなぁ...

 

方法

とりあえず、Google ノートブックを普通にブックマークする。

その後、ブックマークのプロパティを開き、URL に以下を設定する。

http://www.google.com/notebook/fullpage#q=%s

080320-001

キーワードは、適当につける。

 

関連記事

2008年3月19日水曜日

アニクリ 「ナミダの向こう・・」と「羽」

押井守が好きで、番組に名前が含まれていた場合、自動的に録画するようにビデオを設定している。そうしたら、NHK の BS でやっていた「アニクリ」という番組が録画されていた。

この番組、企画の主旨が変っている。日本を代表するアニメ・クリエーターが、" 1 分"という枠でアニメを作成するというものだ。この中に、押井守も参加していたので、ビデオに録画されたようだ。

 

15 組のアニメクリーターの作品の中で、一番よかったのが、林明美の「ナミダの向こう・・」。

 

15 組の中で、一番オーソドックスなテーマだったけれど、よくできているとしか言いようがない。

 

また、この中で使われている音楽がイイ。I's CUBE(アイス・キューブ)という名前のグループ。音楽はいいし、声も好き。ちょっとハスキーで、特にサビの部分の裏声の使い方がイイナ~。(ちょっと、ピョークを連想するところがある。)

 

こうやってタダで音楽が聴けたり、音楽の不正コピーが言われるようになって久しいけれど、やはりいいものは購入して、自分の手元に置きたくなる。そういう意味で、今の時代、支えられている技術の上で、アーティストの価値の問われ方が変化しているのだと実感する。「それでも、手に入れたい」と思わせることができる人たちのみが生き残っていく。イヤハヤ、たいへんな商売であり、商品だと思う。 (@_@;)

羽
I’s CUBE 宇治田愛

インディーズ・メーカー 2007-06-06
売り上げランキング : 20463

Amazonで詳しく見る
by G-Tools

 

ところで、アニクリの中で、一番これが笑えた。 ^^

Access でテキストボックスを「縦書き」にする

テキストボックスのプロパティ > その他 > 縦書き

080319-001

 

書式ではないのかぁ... (@_@;)

 

参考サイト

2008年3月18日火曜日

Access でクロス集計クエリを作成するとき、列見出しを固定して、全ての「月」を表示する

1. 「月」のレコードがないと、クロス集計クエリに基づいたレポートで、レコードのない「月」は表示されない

Access のクロス集計クエリは、クロス集計をする対象のレコードがないと、集計基準の「列」に表示されない。

例えば、

ある項目に対して、月ごとのクロス集計を作成したい

場合、ある月のレコードがないと、クエリの結果の列に、その月が表示されない。よって、このクロス集計クエリに基いたレポートを作成するのは難しい。

 

2. 「クエリ列見出し」を固定する

全ての月を表示するには、080318-001クロス集計クエリのプロパティの

  • クエリ列見出し

に 1 ~ 12 (月) を入力しておく。

これにより、データがなくても列に月が表示されるようになる。

このクロス集計クエリに基いたレポートを作成すれば良い。

 

参考サイト

関連サイト

2008年3月17日月曜日

Access で、二つ以上のテーブルからクエリを作成するとき、同じ名前のフィールドに気をつける

A テーブルは、

  • id : 主キー
  • cd : コード

B テーブルは、

  • id : 主キー
  • cd : コード
  • a_id : A テーブルの id を外部参照

 

A テーブルと B テーブルより、C クエリを作成した。

C クエリは、

  • B.id
  • B.cd
  • A.cd

このとき、B.cd と A.cd というように、 cd共通していた。 C クエリは問題なく動作した。

ここで、C クエリから C レポートを作成することにした。ウィザードを利用して、作成したところ、以下のようなエラーが表示された。

指定したレポートをプレビューできません。他のユーザがソース テーブルを排他モードで開いている可能性があります。

???

なんのこっちゃ (@_@;)

一度、レポートをデザインモードで開き、再度、プレビューで開いてみたら、今度は、

指定されたフィールド 'B.cd' が SQL ステートメントの FROM 句にある複数のテーブルを参照しました。

 

指定されたフィールド’○○○’がSQLステートメントのFROM句にある複数のテーブルを参照しました --Access Club Access 初・中級者 FORUM-- によると、

たとえば、Aテーブル、Bテーブル両方に[コード]フィールドがあったとき、
Select コード
From Aテーブル,Bテーブル
というようなSQLを実行した場合に上記のエラーが出ます。
最初の「コード」は、Aテーブル、Bテーブルどちらの[コード]を表示すれば
良いのか分からない(?)からです。

 

そこで、 C クエリを開き、SQL を表示させ、B.cd という指定を以下のように変更した。

B.cd as Bcd

クエリを GUI で作成する場合には、B.cd というフィールドの値を、 Bcd : B.cd というように指定すればよい。

これで、レポートのプレビューが開けるようになった。 ^^

Firefox で検索フィールドのないサイトに「スマートキーワード」を設定する

1. スマートキーワードで検索

Firefox には「スマートキーワード」という検索機能がある。

Firefox サポート - チュートリアル - 様々な Web 検索機能 によると、

ロケーションバーから簡単に Web サイトを検索できるようにするもう一つの仕組みです。

スマートキーワードが設定してあるサイトでは、ロケーションバーに

キーワード 検索ワード

と入力することで検索を行うことができる。

 

楽天にスマートキーワードを設定して検索した場合

例えば、楽天市場 にスマートキーワードを設定しておけば、(ここでは rk)

rk オメガ スピードマスター

SnapCrab_No-1383

とロケーションバーに入力すれば、オメガ スピードマスターを楽天から検索できる。

SnapCrab_No-1386

 

2. スマートキーワードの設定方法

スマートキーワードの設定を「楽天市場」を例に取り上げて行う。

  1. 楽天の検索サイト内にある「検索するためのフィールド」で、右クリック > この検索にキーワードを設定 SnapCrab_No-1384
  2. ダイアログが表示されたら、
    1. 名前」を適当につける。
    2. 「フォルダ」を適当に選択する。
    3. キーワード」には、短かい文字を英数でつける。SnapCrab_No-1382

キーワードは短い方が検索しやすくなる。ただし、他のスマートキーワードと重複しないように気をつけること。

 

3. 検索フィールドのないサイト内を検索

ただし、ウェブサイトには、必ずしも検索のためのインターフェイスがあるとは限らない。

例えば、「The Haskell 98 Language Report」(http://www.sampou.org/haskell/report-revised-j/index.html)には検索フィールドがない。そのため、Goolge のサイト内検索を利用して検索する必要がある。

検索したい言葉 site:www.sampou.org inurl:haskell/report-revised-j/

site: は、Google検索の秘訣――第5回 信用できる情報を収集したい によると、

「site:」コマンドを使った検索は、「ドメイン制約検索」とか「ドメイン指定検索」と呼ばれています。これは、Googleの検索オプション画面では、「ドメイン」の検索オプションに相当します。

inurl: は、Google検索の秘訣――第7回 教えてもらったあのサイト、何だっけ? によると、

  • 「inurl:」コマンド

WebページのURL文字列に限定して検索します。

サイト内検索を毎回入力するのは面倒なので、スマートキーワードを設定しておきたい。

 

新しくブックマークを作成し、スマートキーワードを付ける

The Haskell 98 Language Report」の場合、新しくブックマークを作成し、上記のサイト内検索をしたときの URL を参考にして、以下の URL を入力する。

http://www.google.co.jp/search?q=%s+site%3Awww.sampou.org+inurl%3Ahaskell%2Freport-revised-j%2F

%s がスマートキーワードで単語を検索したときに、検索対象の単語が渡される変数を表わす。

 

関連記事

2008年3月13日木曜日

Access でテキストボックスを日付入力に適した型にする

フォームデザインにおいて、テストボックスのプロパティ > データ > 定型入力 を選択し、定型入力ウィザードを起動する。

080313-008

 

日付の定型入力を選択して、完了ボタンを押す。

080313-010

 

結果、テストボックスに入力しようとすると定型入力の状態になる。

080313-012

 

参考サイト

2008年3月10日月曜日

Access で複数のサブフォーム間でのフォーカスの移動

サブフォーム間を移動するためのショートカットキー

サブフォーム間を移動するためのショートカットは、 Ctrl + Tab 。サブフォーム内で Tab キーを押し続けると、サブフォーム内に限定されたレコード間のフォーカスの移動が行われる。帳表の形式である場合、通常の入力において、サブフォーム内の新しいレコードを追加するための動作が生じる。

 

1 対 1 のサブフォーム

あるフォームに、複数のサブフォームを存在させることがある。その中に、親となるフォームに対して、 1 対 1 の関係にあるサブフォームがあるとする。この場合、データの入力において、タブキーを押し続けると、上記と同様に、サブフォーム内で新しいレコードを追加しようとする動作が生じる。 親フォームに対して 1 対 1 の関係のサブフォームなので、そのまま追加すると、主キーの制約違反の通知がされる。

1 対 1 の関係である場合、最後のフィールドの入力が終ったら、レコード追加の動作が生じるのではなくて、できれば、次の入力フィールドへ移ってほしい。例えば、入力中のサブフォームから、別のサブフォームのフィールドへフォーカスが移ってほしい場合、入力が終ったフィールドの「フォーカス喪失時」のイベントにおいて、以下のようなコードを記述することによって、タブキーによるスムーズなデータの入力を実現できる。

Forms!フォーム名!サブフォーム名.SetFocus

フォーカスされた方のサブフォームでは、「フォーカス取得時」のイベントで対応する。

RTM は IE コンポーネントを使った軽いブラウザで - KIKI

Firefox は RTM を使うのには向かない。理由は二つ。

  • IME が「直接入力」の状態になっていないと、項目を追加するためのショートカットキー (t) を使えない。
  • セレクトボックスで、マウスホイールによるスクロールができない。

前者は致命的。項目の追加は素早く行いたい。そういうときに、IME の状態を考慮しなくてはいけないのは面倒。また、項目を入力する度に、直接入力と日本語入力を切替えるのは非常に手間。

(追記(2008.6.19) : Firefox 3 になったら、IME の切替えをしなくても入力できるようになった。^^ )

後者は、作成しているリストの数が少なければ問題なし。しかし、自分はリストをたくさん作る運用をしているので、これまた適さない。 ^^;

上記二つは、IE において問題なく使うことができる。日本語入力ができる状態で t のキーを押せば、すぐに日本語を入力することができるし、また、セレクトボックスでマウスホイールを使うこともできる。しかし、普段使っているのは、Firefox 。 RTM のためだけに IE を起動するのもどうかと。自分のパソコンは、そんなに性能がいいわけではないので、IE の起動には少し時間がかかる。

RTM は常に起動しておきたい。気がついたことがあったら、忘れないうちにメモをしておきたいからだ。いつも起動している Firefox で管理できればそれに越したことはないけれど、今回は諦めた。しかし、何もかも Firefox でということに固執することはない。Firefox 以外のブラウザとは独立したブラウザで入力すれば、ひらめいたときに、タスクバーを見ればアプリをすぐに探し出すことができるメリットもある。

さて、問題は IE をどうするか。軽くて、IE 系のブラウザを探すことにした。

KIKI

ブラウザ KIKI 、特質はコンパクトさと起動の速さとツリー管理 によると、

いつも感じるのですが、この KIKI というブラウザは好感がもてます。 ...

立ち上がりは、他のどのブラウザよりも速いのではないでしょうか。1秒とかかりません。 レイアウトもいいですね。すっきりしています。

080310-001ウェブブラウザ KIKI のホームページ からダウンロードして試してみた。確かに、起動が目茶早い。 (@_@;) 瞬間に立ち上がる。これなら RTM 用のセカンドブラウザとして利用しても抵抗がない。

設定

起動時に、 RTM のページが表示されるようにした。

お気に入りに、「start」 (任意の名称) という名前のフォルダを作成し、 RTM のページを登録。

メニューより、ツール > KIKIオプション > 基本設定。起動をするときの動作 > 「起動時に開くページ」を「お気に入りフォルダ」にして、「お気に入りフォルダ」に、新たにお気に入りに作成した「start」を指定した。複数のページを指定できるようだったので、Prism で起動していた Google カレンダーも試しに KIKI で起動するようにしてみた。

その他

KIKI をいつも起動しておくようにしていると、 Firefox で見ているサイトを IE で開きたいときに便利なプラグインが必要ないことに気がついた。IE ViewIE Tab を利用していたが、Firefox で見ているサイトを KIKI で見たい場合は、シンプルにアドレスバーに表示される favicon をつかんで、KIKI に D&D 。頻繁に切替えるわけではないので、これで十分だ。

080310-002

2008年3月9日日曜日

FileMaker と Access の入力フォームにおける操作モデルの違い

FileMaker、Access ともにデータを入力するためのフォームをお手軽に作成できる。 FileMaker に慣れていると、 Access のフォームにおいて、微妙な挙動の違いに気がつく。

 

FileMaker の入力フォーム

FileMaker は、フォームの入力に際して、「新規レコード」を作成しなくてはいけない。(フォームを作成して、はじめてフォームが表示されるときには、「新規レコード」が一つ作成された状態になっている。)

20080309fm1

 

そのため、「レコード削除」をして、すべてのデータを削除した状態でフォームに入力しようとすると、「新規レコード」を作成するように促される。

080309-003

 

つまり、「フォームにおける入力する場」と、「レコードの存否」が対応している。

 

Access のフォーム

これに対して、Access のフォームは FileMaker の動作とは異なる。以下のフォームは、対応するテーブルにデータが全く入力されていない状態である。

080309-007

 

メニューを見ても、レコードの削除はできない。よって、テーブルにデータはない。

080309-008

 

ここで FileMaker との違いが浮き彫りになる。 FileMaker と同じつもりで、「新規レコードを作成する」に相当する「新しいレコード」を選択しよう思っても選択できない。

080309-009

 

しかし、不思議なことに、フォームにデータを入力しようとすると、データを入力することが可能だ。そして、入力をしたと同時に、上記の「レコードの削除」と「新しいレコード」の選択ができるようになる。

つまり、Access においては、FileMaker の「フォームにおける入力する」が、フォームを開くと同時に自動的に生成されていると類推することができる。ただし、その「場」は全く性質が異なる。フィールドへ入力しただけでは、テーブルにデータは反映されない。意識的に「レコードの保存」を行うか、または、「次のレコードへ移動する」か、「フォームを閉じる」とテーブルに反映される。 FileMaker のように、新規レコードを作成したときにレコードが保存されるのに比べると複雑に感じる。

Access では、フォームに入力しただけでは、データは登録されない。「フォームに入力する場」はあるけれど、テーブルからは独立しているようなものと言えばよいのかな。

 
オートナンバー型

例えば、オートナンバー型のフィールドがあった場合、オートナンバー型以外のフィールドへの入力がされたときになって、はじめてオートナンバーが生成される。

 

面倒になること

例えば、以下のように、あるフォームに新しいレコードを作成するときに、同時にそのデータに対応する他のデータを作成したいということがあったとする。

  1. レコードを作成する
  2. 特定のルールによって、上記に対応するデータを作成する

FileMaker においては、新規レコードを作成する処理において、同時にデータを作成する処理を加えればよいはずである。これに対して、Access ではデータを生成するタイミングに気をつけなくてはならない。

 

例えば、新規ボタンを押さなければ、フィールドに入力できないように VBA でコントロールする。新規ボタンを押したときに、レコードを保存し、それと同時に対応するデータを作成。そして、作成したデータを再度フォームに読み込むという手続きをとる必要がある。

手順をまとめると...

  1. ユーザがフォームを表示させる。
  2. システムは、フォームのフィールドを操作できないようにする。
  3. ユーザは、「新規ボタン」を押す。
  4. システムは、フォームに対応したレコードをテーブルに保存する。同時に、そのレコードに対応した他のテーブルのデータを生成し、テーブルに保存する。フォームの内容をリフレッシュすることによって、ユーザにデータを提示。その後、フォームのフィールドを操作できるようにする。
  5. ユーザはデータを入力する。

 

新規レコードの作成においては、フォームの .NewRecord で、テーブルに反映されてないフォームの内容であることを確認した場合、フィールドのロックを解除してデータの生成。そうでない場合は、「新しいレコード」を作成してからロックを解除して、データの生成をする。

 

うーん 、なんかややこしい。方法が間違ってるのかな... ^^;

Ruby で行頭の空白文字を削除する

プログラムの途中の文をブログに貼り付けるとき、行頭の一定数の空白を削除したいことがある。

例えば、次のプログラムの先頭から 4 つの空白文字を取り除きたい。

    If (MsgBox("本当に削除してもよろしいですか?", vbOKCancel) = vbCancel) Then
       Exit Sub
   End If

以下のように、__END__ 以下に上記のプログラムを貼り付け、スクリプトを実行する。

DATA.each do |line|
 puts line.sub(/^\s{4}/,"")
end


__END__
   If (MsgBox("本当に削除してもよろしいですか?", vbOKCancel) = vbCancel) Then
       Exit Sub
   End If

参考サイト

Access でダイアログボックスを表示して、ユーザに Yes, No を選択させる

MsgBox 関数 を利用し、引数に vbOKCancel をとる。

MsgBox(prompt [, buttons ] [, title ] [, helpfile ] [, context ] )

prompt 必ず指定します。ダイアログ ボックス内にメッセージとして表示する文字列式を指定します。引数 prompt に指定できる最大文字数は、1 バイト文字で約 1,024 文字です。

vbOKCancel [OK] ボタンと [キャンセル] ボタンを表示します。

(MsgBox 関数 - Access - Microsoft Office Online より)

. レコードを削除する前に、ユーザに確認をとるためのダイアログを表示する。

If (MsgBox("本当に削除してもよろしいですか?", vbOKCancel) = vbCancel) Then
   Exit Sub
End If

   ' 処理を続ける...

080309-001

関連サイト