ページ内ジャンプ:

アレゲなニュースと雑談サイト

ruto の日記から検索

ruto (17678)

ruto
(メールアドレス非表示)

./の日記のRSS [slashdot.jp] 日記本文や、そこからリンクされているhttp://www.aya.or.jp/~takuo/以下の画像の、Tumblrへの転載を許可します。リンクなどで転載元がわかるようにしておいてください。
2009 年 03 月 28 日
PM 03:26
プログラミング

正規表現より文脈自由文法の方が良いという意見に対する正規表現の擁護
「正規表現が手軽だから」以上が無くて、言語の表現力の話とリテラルとしての正規表現の話がごっちゃになってる気がする。この論法だと、正規表現から上位のクラスの言語用のパーサへ変換する機能を用意されたらそれでいいことになってしまう。

スクリプト言語の機能としての正規言語マッチャは、使う側としては、正規言語(+α)に限れば圧倒的に速くパースできるという以上のメリットは無いと思う。「チューリングマシンが最強」というのは確かで、パーサコンビネータとか手書き再帰下降パーサとかは0型の文法でもパースできて最強だと思う。速度以外は。

もちろん研究者としては機能が制限されてる方がいろいろ性質を保証できたり解析できたりして嬉しいけど、スクリプト言語を使う側にとってそれを生かした便利な機能って、速度とか停止性ぐらいしか今のところないんじゃないだろうか。

速いから正規言語に限るんであって、速度を犠牲にしても良いんなら上位のクラスの言語用の機能だけ用意して、正規表現からそれに変換すればいいと思う。

追記:
見直してみたら、元から正規表現対BNFの話のようです。話をごっちゃにしてたのは私の方だったようです。

2008 年 12 月 20 日
AM 01:19
日記

こんなん作った。hello.rb

これは、

foo1 = procedure do foo(1, _, _) end

と書くと

foo1 = proc do |x, y| foo(1, x, y) end

とほぼ同じことになる。

途中で例外が起きたり、callccを使うと変になるはず。

あと、

procedure do 2.times do p _ end end

は1引数手続きではなく2引数手続きになって、_の値は1回目のループでは1つめの引数、2回目のループでは2つ目の引数になる。

shift/reset言いたかっただけなので、実はもっと簡単に書ける。

def procedure
  proc do |*args|
    old_index = Thread.current[:index]
    old_args = Thread.current[:args]
    Thread.current[:index] = 0
    Thread.current[:args] = args
    begin
      yield
    ensure
      Thread.current[:index] = old_index
      Thread.current[:args] = old_args
    end
  end
end

def _
  Thread.current[:index] += 1
  Thread.current[:args][Thread.current[:index] - 1]
end

これは例外には対応しているけど、やっぱりcallccに対応していない。

2008 年 07 月 21 日
AM 04:40
日記

『ジェネレーティブプログラミング』という本を読んでいる。といっても前半は飛ばしたし、後半もあまり読めてないんだけど。
そこで構成レポジトリというのがでてきておもしろい。

例えば行列計算ライブラリを作るとする。
行列は要素の型がfloatだったりdoubleだったり複素数だったり、行列で使うベクトルの型も行列の種類によって違ったりして、その組み合せは膨大になる。
そのため、C++ならテンプレートを使って、行列クラスは要素の型やベクトルの型を受け取るようにするとよい。
つまり、

template<class ElementType, class VectorType>
class Matrix {
  (ElementTypeやVectorTypeをここで使う)
}

みたいな感じ。
このとき、要素の型とベクトルの型を両方いちいち指定するのはめんどうなので、まとめてどこかに1つだけ書いておいて、それを参照するようにできると便利。
それが構成レポジトリと呼ばれるものである。つまり、

struct FooConfigrationRepository {
  typedef double ElementType;
  typedef FooVector<ElementType> VectorType;
}

と書いておいて、

template<class Config>
class Matrix {
  (ElementTypeの代わりにConfig::ElementTypeを使う)
}

という風にMatrixの方を書き換えておけば、FooConfigrationRepository1つを渡すだけで済むので楽だし、後で変更するときもここだけ変えればいいので楽になる。

というのが構成レポジトリのごく簡単な説明。
ただ、『ジェネレーティブプログラミング』ではC++での例は載っているけど、Javaの例は載っていない。
そもそもJavaではクラス内でtypedefできないのでC++と同じようにはできない。

しかし、JavaでもGenericsを使えば似たようなことはできる。
まず、構成レポジトリは次のように書く。

interface ConfigrationRepository<ElementType extends ElementInterface, VectorType extends VectorInterface<ElementType>> {
  VectorType createVector(int size);
  ...
}
 
class FooConfigrationRepository implements ConfigrationRepository<Double, FooVector<Double>> {
  public FooVector<Double> createVector(int size) {...}
  ...
}

それで、受け取る方は次のように書く。

class Matrix<ElementType extends ElementInterface, VectorType extends VectorInterface<ElementType>, Config extends ConfigrationRepository<ElementType, VectorType>> {
  (ElementTypeやVectorTypeを使う)
}

それで、これらのライブラリを使う場合には次のようにする。

class Main {
  public static void main(String [] args) {
    start(new FooConfigrationRepository());
  }
  <ElementType extends ElementInterface, VectorType extends VectorInterface<ElementType> Config extends ConfigrationRepository<ElementType, VectorType>> void start(Config config) {
      Matrix<ElementType, VectorType, Config> bar = new Matrix<ElementType, VectorType, Config>(config);
      ...
  }
}

つまり、例えばFoo<Double, Integer>という型を、2つの型DoubleとIntegerを要素として持つレコードとして使っている。
そこから要素を取り出すときは、<X, Y, Z extends Foo<X, Y>>という風にパターンマッチを使って取り出している。

ただ、C++に比べて記述はかなり汚なくなっていてあまり実用的ではないし、ここまで凝ったことはJavaではやらないのがJavaの流儀っぽい気がする。

# JavaのGenericsっていままで詳しく調べたことなかったので、実はもっとスマートな方法があるかもしれない。

2007 年 12 月 07 日
PM 11:34
ゲーム

スーパーマリオブラザーズに対するツッコみとして、レンガに変えられたキノコ王国住民を破壊するのはどうよ、ってのがよくある。

しかし、説明書には次のような記述がある

レンガに変えられたり、消されたりしたキノコを見つけて助けると、彼等からパワーをもらって、次々と変身します。

ここから考えると、壊れるブロックはただのブロックで、叩くとアイテムが出るブロックがキノコ王国住民なんじゃないだろうか。

消されたりしたキノコってのは隠しブロックのことで。

2007 年 10 月 28 日
PM 10:17
入力デバイス

今までOrbit Optical使ってたんだけど、ボタンがへたってきたのでポインティングデバイスを買い替えることにした。

またOrbit Optical買ってもいいんだけど、もうちょっと冒険してみようと思って、空中マウスの一種であるMX Airを買ってみた(腕のねじれないデバイスが欲しかった)。

で、繋いでみたところ、専用ドライバの無いLinuxでもある程度は使えた。以下詳細。

  • デスク上での移動
    → 通常のマウスの動き
  • 左右ボタン
    → 左右ボタン
  • 空中での移動
    → 通常のマウスの動き
  • ホイールをゆっくり撫でる
    → ホイールイベント
  • ホイールをすばやく動かして話す
    → 連続したホイールイベント(手を離した後も発生)。音もマウスからでる。
  • ホイール上の上下ボタン
    → ホイールイベント(オートリピート有り)
  • BACKボタン
    → サイドボタン(input.hで言うところのBTN_SIDE)
  • BACKボタンを2秒以上押す
    → 空中でのカーソル移動停止
  • SELボタン
    → 左クリック(BTN_LEFT)
  • 再生/一時停止ボタン
    → 出力無し(ただし、押しながらジェスチャをすると本体から音は出る)(追記: 別デバイスファイルで、クリック時に再生/一次停止(KEY_PLAYPAUSE)イベントを出力、ジェスチャで次の曲/前の曲(KEY_NEXTSONG/KEY_PREVIOUSSONG)イベントを出力。)
  • VOLボタン
    → 出力無し(ただし、押しながらジェスチャをすると本体から音は出る)(追記: 別デバイスファイルで、クリック時にミュート(KEY_MUTE)イベントを出力、ジェスチャで音量調節(KEY_VOLUMEDOWN/KEY_VOLUMEUP)イベントを出力)

SELが左ボタンと同じイベントなのと、再生/一時停止ボタンやVOLボタンが認識されてないのが痛い。それ以外はまぁまぁ。

さらに自作ツールでevdevを調べてみたところ、以下のイベントを発生させると宣言している。

Event type 0x00  (Sync Events)
  Report  Config
Event type 0x01  (Keys or Buttons)
  Mouse Button Left  Mouse Button Right  Mouse Button Middle  Mouse Button Side  Mouse Button Extra  Mouse Button Forward  Mouse Button Back  Mouse Button Task  Unknown 0x118  Unknown 0x119  Unknown 0x11a  Unknown 0x11b  Unknown 0x11c  Unknown 0x11d  Unknown 0x11e  Unknown 0x11f
Event type 0x02  (Relative Axes)
  X  Y  Horizontal Wheel  Wheel

以下追記

音量調節ボタンなどは別のデバイスファイルに割り当てられる。それらは以下のイベントを出力すると宣言している。

Event type 0x00  (Sync Events)
  Report  Config
Event type 0x01  (Keys or Buttons)
  Mute  Volume Down  Volume Up  Pause  Stop  Props  Undo  Copy  Paste  Find  Cut  Help  Calc  Sleep  File  WWW  Mail  Bookmarks  Back  Forward  Eject CD  Next Song  Play/Pause  Previous Song  Stop CD  Record  Rewind  Config  Homepage  Refresh  Scroll UP  Scroll DOWN  Unknown 0xb5  Unknown 0xb6  Play  Fast Forward  Bass Boost  Print  Unknown 0xe7  Unknown 0xe8  Unknown 0xe9  Unknown 0xea  Unknown 0xeb  Button 0  Program  Radio  Channel Up  Channel Down
Event type 0x02  (Relative Axes)
  Horizontal Wheel
Event type 0x03  (Absolute Axes)
   Volume        value 0 minimum 1 maximum 652 fuzz 0 flat 0

同梱されているWindows用のユーティリティー(SetPoint)で設定した設定はハードウェアに保存されるわけではないらしく、Linuxでは有効にならない。ただ、前述のプログラムの出力を見ると、キーのカスタマイズはソフトウェアによる変換ではなく、ハードが直接別のイベントを出力しているのだと予想できる。おそらく、なんらかのコマンドを送るとハードウェアが別のイベントを送信するようになるのではないかと思う。

2007 年 07 月 11 日
AM 05:39
Mozilla

Firefox用拡張でRadialContextというのがあって、これを使うと普通のコントキストメニューの代わりにドーナツ状のパイメニューがポインタの周りに出るようになる。
素晴しいのはポインタをドーナツの外に動かそうとしてもちゃんとメニューがポインタに付いてくる点で、マウスジェスチャーの感覚で使える。しかもマウスジェスチャと違ってアイコンが表示される上、ポインタを動かさないでいると説明テキストが出るので、割り当てを忘れてしまっても大丈夫。
これがあるお陰で私は他のブラウザを使えない。

だけど、けっこう前からしばらく使っていると突然メニューが動かなくなって、しかもマウスやキーボードのイベントをグラブしたままになるのでFirefoxがまともに使えなくなくなってしまう。

これじゃ使いものにならないってんで調べてみたところ、とりあえず対症療法が見付かった。
rcMenu.jsでラベルのfontWeightを設定しているところでエラーが出ていた。
設定しているところは幾つかあってその内1つでは
try {...} catch(ex) {dump("Why does setting the font weight fail sometimes?\n" + ex.toString() + "\n");}
という風に例外をキャッチしているが、その他の部分では例外をキャッチしていない。これが原因っぽい。
また、showLabelsの
this.lnode.style.lineHeight= 20*100/currentZoom+ "px";
this.lnode.style.fontSize= 8*100/currentZoom+ "pt";
の部分でも例外が起きている。
とりあえず例外が起きている部分を、try...catch...で囲むと、今のところ一応動いてる。
エラーメッセージにあるように、この例外がなぜ起きるのかは謎なので根本的な解決にはなってない。

おまけ:
application/xhtml+xmlなページでパイメニューが表示されないのは、rcIntegration.jsの
pie_context.body= pie_context.frame_doc.getElementsByTagName("BODY")[0];
というところで大文字の"BODY"を指定してるのが原因っぽい。その後に
if (!pie_context.body) {
        pie_context.body= pie_context.frame_doc.getElementsByTagName("body")[0];
}
を入れてみると表示される。

2007 年 06 月 11 日
AM 11:30
入力デバイス

グラフィカルなCLI系でまた1つ。

Hotwire

  • Pythonで書かれていて、パイプラインの中はPythonオブジェクトが通る。
  • レンダラを登録することでオブジェクトの表示方法をカスタマイズできる。
  • プログラミング言語であることを目指していない。
  • 普通のコマンドも使える。端末制御にも対応。
  • 他のマシンでコマンドを実行してローカルマシンで結果を表示することも可能。

あと、類似プロジェクトのリストが参考になる。けっこうあるもんだな。

2007 年 06 月 03 日
AM 03:23
入力デバイス

viやEmacsを使うことは、先験的であり超越論的である

GUIエディタよりコマンドラインエディタが本質的に優れているなどという理由では、決してない。

(既存の)GUIの設定ツールによる管理の悪い点はコピペしたりできない点。個々のテキストフィールドはコピーできるけど、設定画面全体のコピペはできない。

GUIもコピペしたりファイルに保存できればいいのに。と思ったけど、「それなんてxfy?」だな。

ところで、元エントリは一般的なGUI vs CLIの話なのか、viという具体的なテキストエディタの良し悪しの話なのか、専用管理ツールによる管理 vs 汎用テキストエディタによる管理の話なのか読み取れない。

2007 年 05 月 28 日
AM 05:13
入力デバイス

以前から言っているグラフィカルなコマンドラインインターフェースは、入力はテキストで、出力はグラフィックスというものだった。

しかし、コマンドラインが敬遠される理由としては、学習コストの高さが挙げられる。実際私もLinuxのコマンドの細かいオプションまでは覚えきれない。

そこで、入力の方にもグラフィカルな、入力の補助インターフェースを付けてみてはどうかと思い、例によって絵を描いてみた。

入力も出力もグラフィカルなコマンドラインインターフェース

ムービーの再生が終了して、grep的なコマンドを入力しているところという設定。

以下説明兼アイデアメモ

  • コマンドを簡単にコピペしたり、ファイルに保存できることは重要なので、下には生のコマンドが表示される。
  • 入力はキーボードで生のコマンドを直接書いても良いし、GUIで操作しても良い。当然両者は連動している。
  • 最初に左のボタンで、コマンドを選び、次に引数を決定する。
  • 実行するとその下に結果が出力され、終了すると新しい入力GUIが出てくる。
  • バックグラウンドで実行する場合即座に次の入力GUIが出てくる。バックグラウンドの出力は対応する入力GUIの下の領域に追加されていくので、複数のジョブの出力が混ざることはない。
  • パイプやヒストリーをどう表すかは未定。

ただ、このインターフェースはプログラマーに負担をかけるので良くない。古き良きUNIX的な環境を作りたいのにWIMPを使ったGUIを構築しないといけないのは良くない。

ちなみに、入力がテキストで出力がグラフィカルなやつはFirefoxの拡張としてプロトタイプを作成中。Firefoxの拡張作るのめどい。

XULはインターフェースだけで、シェルとしての処理はRubyで書いたサーバーで実行。今のところ、dateと入力するとカレンダーが出力される程度。将来的にはコマンドを任意の言語で書けるようにしたい。パイプの中はMultipart風な構造でJSONのストリームが流れる予定。

PowerShellみたいにコマンドを実装する側にいろいろ制約をかけてしまうのはありだけど、あんまりやりたくない。それで得られるものもあるからある程度は制約をかけないといけないんだろうけど、ほとんどのプログラミング言語で、特別なライブラリ無しでもコマンドを書けるようにしたい。

もし公開する場合はシェルとしてではなくファイラーというカテゴリで出す予定。そっちのほうが使う側の心理的な障壁や要求が低いイメージがあるので。

2007 年 05 月 24 日
AM 03:19
入力デバイス

20Qインターフェースというのはどうだろうか。
コンピュータ「インターネット関係?」
ユーザー「いいえ」
コンピュータ「音楽関係?」
ユーザー「いいえ」
コンピュータ「写真関係?」
ユーザー「はい」
コンピュータ「わかったよ! 新しく撮ってきた写真を印刷したいんでしょう?」
ユーザー「あたり!」

ただ、これを使うには、自分が何をしたいかをはっきりと意識しないといけないのでイマイチかも。