2005 6 7 8 9 10 11 12
2006 1 2 3 4 5 6 7 8 9 10 11 12
2007 1 2 3 4 5 6 7 8 9 10 11 12
2008 1 2 3 4 5 6 7 8 9 10 11 12
2009 1 2 3 4 5 6 7 8 9 10 11 12
2010 1 2 3 4 5 6 7 8 9 10 11 12
2011 1 2 3 4 5 6 7 8 9 10 11 12
2012 1 2 3 4 5 6 7 8 9 10 11 12
2013 1 2 3 4 5 6 7 8 9 10 11 12
2014 1 2 3 4 5 6 7 8 9 10 11 12
2015 1 2 3 4 5 6 7 8 9 10 11 12
2016 1 2 3 4 5 6 7 8 9 10 11 12
2017 1 2 3 4 5 6 7 8 9 10

ホーム

2010年02月26日

JRubyに移すときもそうだったんですけど、基本的に
Javaのコードを整えてからJRubyなりClojureなりに
移すという手順を取ります。そうでないと、JRubyなり
Clojureなりに移してからゴチャゴチャいじるハメに
なって、どこで間違えたかわからなくなってしまいます。

で、JRubyに移すときは、割と単純にできたんですけど、
Clojureとなると大変です。気軽に代入が使えません。

これはSpringUtilitiesというクラスのコードです。
ちょっと長いんですけど:

    public static void makeGrid(Container parent,
                                int rows, int cols,
                                int initialX, int initialY,
                                int xPad, int yPad) {
        SpringLayout layout = (SpringLayout)parent.getLayout();
        Spring xPadSpring = Spring.constant(xPad);
        Spring yPadSpring = Spring.constant(yPad);
        Spring initialXSpring = Spring.constant(initialX);
        Spring initialYSpring = Spring.constant(initialY);
        int max = rows * cols;
        Spring maxWidthSpring = layout.getConstraints(parent.getComponent(0)).
                                    getWidth();
        Spring maxHeightSpring = layout.getConstraints(parent.getComponent(0)).
                                    getWidth();
        for (int i = 1; i < max; i++) {
            SpringLayout.Constraints cons = layout.getConstraints(
                                            parent.getComponent(i));
            maxWidthSpring = Spring.max(maxWidthSpring, cons.getWidth());
            maxHeightSpring = Spring.max(maxHeightSpring, cons.getHeight());
        }
        for (int i = 0; i < max; i++) {
            SpringLayout.Constraints cons = layout.getConstraints(
                                            parent.getComponent(i));
            cons.setWidth(maxWidthSpring);
            cons.setHeight(maxHeightSpring);
        }
        SpringLayout.Constraints lastCons = null;
        SpringLayout.Constraints lastRowCons = null;
        for (int i = 0; i < max; i++) {
            SpringLayout.Constraints cons = layout.getConstraints(
                                                 parent.getComponent(i));
            if (i % cols == 0) {
                lastRowCons = lastCons;
                cons.setX(initialXSpring);
            } else {
                cons.setX(Spring.sum(lastCons.getConstraint(SpringLayout.EAST),
                                     xPadSpring));
            }

            if (i / cols == 0) {
                cons.setY(initialYSpring);
            } else {
                cons.setY(Spring.sum(lastRowCons.getConstraint(SpringLayout.SOUTH),
                                     yPadSpring));
            }
            lastCons = cons;
        }
        SpringLayout.Constraints pCons = layout.getConstraints(parent);
        pCons.setConstraint(SpringLayout.SOUTH,
                            Spring.sum(
                                Spring.constant(yPad),
                                lastCons.getConstraint(SpringLayout.SOUTH)));
        pCons.setConstraint(SpringLayout.EAST,
                            Spring.sum(
                                Spring.constant(xPad),
                                lastCons.getConstraint(SpringLayout.EAST)));
    }

見てのとおり、代入が使われまくってます。で、
これをできるだけ代入を使わないように書き換え
ないとClojureに移すに移せません。その結果:

    public static void makeGrid(Container parent,
                                int rows, int cols,
                                int initialX, int initialY,
                                int xPad, int yPad) {
        SpringLayout layout = (SpringLayout)parent.getLayout();
        Spring xPadSpring = Spring.constant(xPad);
        Spring yPadSpring = Spring.constant(yPad);
        Spring initialXSpring = Spring.constant(initialX);
        Spring initialYSpring = Spring.constant(initialY);
        int max = rows * cols;
        Spring maxWidthSpring = getMaxWidthSpring(parent, layout, max);
        setWidthAll(parent, layout, max, maxWidthSpring);
        Spring maxHeightSpring = getMaxHeightSpring(parent, layout, max);
        setHeightAll(parent, layout, max, maxHeightSpring);
        adjustCells(parent, layout, rows, cols, xPadSpring, yPadSpring,
                    initialXSpring, initialYSpring);

        SpringLayout.Constraints lastCons =
                layout.getConstraints(parent.getComponent(max - 1));
        SpringLayout.Constraints pCons = layout.getConstraints(parent);
        pCons.setConstraint(SpringLayout.SOUTH,
                            Spring.sum(Spring.constant(yPad),
                                       lastCons.getConstraint(SpringLayout.SOUTH)));
        pCons.setConstraint(SpringLayout.EAST,
                            Spring.sum(Spring.constant(xPad),
                                       lastCons.getConstraint(SpringLayout.EAST)));
    }

    private static Spring getMaxWidthSpring(Container parent,
                                            SpringLayout layout, int max) {
        Spring maxWidthSpring =
                layout.getConstraints(parent.getComponent(0)).getWidth();
        for (int i = 0; i < max; i++) {
            SpringLayout.Constraints cons =
                    layout.getConstraints(parent.getComponent(i));
            maxWidthSpring = Spring.max(maxWidthSpring, cons.getWidth());
        }
        return maxWidthSpring;
    }

    private static Spring getMaxHeightSpring(Container parent,
                                             SpringLayout layout, int max) {
        Spring maxHeightSpring =
                layout.getConstraints(parent.getComponent(0)).getHeight();
        for (int i = 0; i < max; i++) {
            SpringLayout.Constraints cons =
                    layout.getConstraints(parent.getComponent(i));
            maxHeightSpring = Spring.max(maxHeightSpring, cons.getHeight());
        }
        return maxHeightSpring;
    }

    private static void setWidthAll(Container parent, SpringLayout layout,
                                    int max, Spring width) {
        for (int i = 0; i < max; i++) {
            SpringLayout.Constraints cons =
                    layout.getConstraints(parent.getComponent(i));
            cons.setWidth(width);
        }
    }

    private static void setHeightAll(Container parent, SpringLayout layout,
                                     int max, Spring height) {
        for (int i = 0; i < max; i++) {
            SpringLayout.Constraints cons =
                    layout.getConstraints(parent.getComponent(i));
            cons.setHeight(height);
        }
    }

    private static void adjustCells(Container parent, SpringLayout layout,
                                    int rows, int cols,
                                    Spring xPadSpring, Spring yPadSpring,
                                    Spring initialXSpring,
                                    Spring initialYSpring) {
        adjustCellsX(parent, layout, rows, cols, xPadSpring, initialXSpring);
        adjustCellsY(parent, layout, rows, cols, xPadSpring, initialYSpring);
    }

    private static void adjustCellsX(Container parent, SpringLayout layout,
                                    int rows, int cols, Spring xPadSpring,
                                     Spring initialXSpring) {
        for (int i = 0; i < rows * cols; i++) {
            SpringLayout.Constraints cons =
                    layout.getConstraints(parent.getComponent(i));
            if (i % cols == 0) {
                cons.setX(initialXSpring);
            } else {
                SpringLayout.Constraints lastCons =
                        layout.getConstraints(parent.getComponent(i - 1));
                cons.setX(Spring.sum(lastCons.getConstraint(SpringLayout.EAST),
                                     xPadSpring));
            }
        }
    }

    private static void adjustCellsY(Container parent, SpringLayout layout,
                                     int rows, int cols, Spring yPadSpring,
                                     Spring initialYSpring) {
        for (int i = 0; i < rows * cols; i++) {
            SpringLayout.Constraints cons =
                    layout.getConstraints(parent.getComponent(i));
            if (i / cols == 0) {
                cons.setY(initialYSpring);
            } else {
                int lastRowIndex = i - i % cols;
                SpringLayout.Constraints lastRowCons =
                        layout.getConstraints(parent.getComponent(lastRowIndex));
                cons.setY(Spring.sum(lastRowCons.getConstraint(SpringLayout.SOUTH),
                                     yPadSpring));
            }
        }
    }

関数型の人はよく『代入が必要なことは(命令型の人が
思ってるほど)多くない』といいます。それは事実なん
でしょう。でも、世のほとんどのコードは命令型で
書かれてます。そして、そういうコードでは代入が使われ
まくってます。ゼロから書き上げるコードならともかく、
上のような移植となると、命令型から関数型に書き換える
のは大変なんです。

本家Permlink


2010年02月25日

オレさ、こういうコード、大っ嫌いなんだよね:

    Spring maxWidthSpring = layout.getConstraints(parent.getComponent(0)).getWidth();
    Spring maxHeightSpring = layout.getConstraints(parent.getComponent(0)).getWidth(); // 今気づいたけど、これは原文ママ
    for (int i = 1; i < max; i++) {
        SpringLayout.Constraints cons = layout.getConstraints(parent.getComponent(i));
        maxWidthSpring = Spring.max(maxWidthSpring, cons.getWidth());
        maxHeightSpring = Spring.max(maxHeightSpring, cons.getHeight());
    }

まずこう書き直す:

    Spring maxWidthSpring = layout.getConstraints(parent.getComponent(0)).getWidth();
    Spring maxHeightSpring = layout.getConstraints(parent.getComponent(0)).getWidth();
    for (int i = 0; i < max; i++) {
        SpringLayout.Constraints cons = layout.getConstraints(parent.getComponent(i));
        maxWidthSpring = Spring.max(maxWidthSpring, cons.getWidth());
        maxHeightSpring = Spring.max(maxHeightSpring, cons.getHeight());
    }

次にこう書き直す:

    Spring maxWidthSpring = layout.getConstraints(parent.getComponent(0)).getWidth();
    for (int i = 0; i < max; i++) {
        SpringLayout.Constraints cons = layout.getConstraints(parent.getComponent(i));
        maxWidthSpring = Spring.max(maxWidthSpring, cons.getWidth());
    }

    Spring maxHeightSpring = layout.getConstraints(parent.getComponent(0)).getWidth();
    for (int i = 0; i < max; i++) {
        SpringLayout.Constraints cons = layout.getConstraints(parent.getComponent(i));
        maxHeightSpring = Spring.max(maxHeightSpring, cons.getHeight());
    }

で、最後にメソッドを切り出す:

Spring getMaxWidthSpring(Container parent, SpringLayout layout, int max) {
    Spring maxWidthSpring = layout.getConstraints(parent.getComponent(0)).getWidth();
    for (int i = 0; i < max; i++) {
        SpringLayout.Constraints cons = layout.getConstraints(parent.getComponent(i));
        maxWidthSpring = Spring.max(maxWidthSpring, cons.getWidth());
    }
    return maxWidthSpring;
}

Spring getMaxHeightSpring(Container parent, SpringLayout layout, int max) {
    Spring maxHeightSpring = layout.getConstraints(parent.getComponent(0)).getWidth();
    for (int i = 0; i < max; i++) {
        SpringLayout.Constraints cons = layout.getConstraints(parent.getComponent(i));
        maxHeightSpring = Spring.max(maxHeightSpring, cons.getHeight());
    }
    return maxHeightSpring;
}

最初の i = 1 にしちゃうってのは、気づきにくい分、
罪が重いんだよね。いや、『i = 1 で全然問題ない
じゃん!』って人もたくさんいると思うんだけど。
少なくともオレは、こういうコードを書く人が書く
コードを疑いの目で見るのね。他のとこでやらかしてる
んじゃないかって。

本家Permlink


2010年02月21日

エヘヘ。ミーハーなもんで、もうちょっとClojureと
付き合ってみようかと。

で、例によってSwing Tutorialをボツボツ移してこうかと。

簡単なもので、でも簡単すぎないものということで:

ButtonDemo.clj

ボタンに貼りつける画像ファイルは別途入手してください:

http://java.sun.com/docs/books/tutorial/uiswing/examples/components/index.html#ButtonDemo

で、移してみた感想なんですけど。

前方宣言というか、前方定義というか、関数を定義する
ときに、その中で使われる名前が解決できてないと
いけないのが辛いです。『あれ? Lispってそうだったっけ?』
と思ってElispで調べたくらい違和感がありました。

たとえば:

(defn doit [] (dothat))
(defn dothat [] (println "hello"))

これはアウト。関数定義の順番を引っくり返す他にも:

(declare dothat)
(defn doit [] (dothat))
(defn dothat [] (println "hello"))

というのも使えます。

一番困ったのがグローバル変数が使えないこと。いや、
使えるんですけど、思ったように使えないというか。
defしたときにすぐに値が束縛できるんなら全然問題
ないんですけど、GUI使うとそうもいかないことも多くて。

ButtonDemo.cljでいえば、冒頭のb1, b2, b3がそれです。
もともとのJavaのコードと見比べてもらえばわかりますけど、
これらはもともとインスタンス変数なんですね。他にも
やり方はあるでしょうけど、こういうインスタンス変数は
グローバル変数に置き換えるのが楽なわけで。

で、これらの変数をdefで束縛することもできるとは思うん
です。たとえば:

(def b1 (JButton.))

みたいな感じで。でも、それやっちゃうともとのコードと
大きく変わっちゃうんですよね。それはイヤだし。

で、最初は:

(def b1)

ってやってたんですよね。あとで束縛し直せばいいやと
思って。でも、調べてみると、束縛し直せないんですよ。
setqもset!もない。いや、set!はあるんですけど、機能が
違うっぽいんですね。

それで調べた結果がrefを使うというやり方。まさか簡単な
GUIプログラム作るのにrefとか使うとは思ってなかったんで、
ビックリしました。refなんて並列プログラミングでも
しないと出てくるもんじゃないと思い込んでましたからね。

他にも戸惑う点はいくつもありましたけど、大きなのは
この2点ですかね。前方宣言とグローバル変数の束縛。
で、この2つを見て『やっぱりClojureは流行んないかも』
って思っちゃいましたね (笑)。

少なくともモダンな動的言語というからには、前方宣言は
カンベンしてほしいですね。コンパイルする必要があると
しても、それを先延ばしにすることはできるんじゃないかと
思うんですよね。まぁ、自分は素人なんで、ただの
ワガママかもしれませんけど。

グローバル変数の束縛は根深いっていうか、Clojureの
存在意義に関わることなんで悩ましいところですけど。
でも、やっぱり、シングル・スレッド前提で書くコードは
すっきり書きたいじゃないですか。自分の書くほとんどの
コードはシングル・スレッド前提だし。

あ、繰り返しますけど、Clojureは全体としていい言語
ですよ。ButtonDemo.cljは、Javaを割と素直に移した
ものですけど、Javaのコードよりすっきりしてると
思うでしょ? もちろん、静的型を書かなくって済むって
いうのもありますけど、dotoとかね。

本家Permlink


2010年02月18日

ペア・プログラミングで易きに流れることもある。特に
パートナーが目上だったりした場合、遠慮というものが
生まれてしまう。

しかし、勇気を与えてくれるのもまたペア・プログラミングだ。
自分一人では怯んでしまうような大きなリファクタリングでも、
励ましてくれるパートナー、道を正してくれるパートナーが
いれば勇気を持てる。

つまり、ペア・プログラミングがうまくいかないのは:

* あなたが(いろいろな意味で)エラすぎる
* あなたが(いろいろな意味で)下ッパすぎる
* あなたに志や熱意が欠けている

といった場合だ。

--

タレブの『まぐれ』は訳者あとがきが面白い:

  本書に出てくる迷信深い人間だの、損益の額よりも損益の頻度で一喜一憂す
  る合理的でない人間だのというのは、とりもなおさずタレブ自身のことなの
  だ。

  (中略)

  エンピリカのトレーディングには、あらかじめ決めたルールがある。タレブ
  の会社だから、タレブ自身はそのルールを変えられる。しかし、そのルール
  を変えるためのルールがまた存在する。そして、彼の周りには、タレブが決
  して「社員」と自称するのを許さない仲間たちがいて、彼の行動を見張り、
  同時に彼を励ましているのだ。毎日損をし続けながらでも、いつかやってく
  る黒い白鳥を待っているのにはちゃんと意義がある、と。

感情を制御するのは難しいのだから、感情に振り回され
ないようなシステムを作り上げる、あるいは、信頼できる
仲間を作るといったように、間接的な対策を講じたほうが
いい。

本家Permlink


2010年02月17日

佐々木常夫の仕事の進め方10か条

東洋経済でこの10か条が出てくるのは2回目です。自分は、
前回の掲載誌を失くしてしまいました。それに気づいた
ときは、かなり残念に思いました。掲載誌を特定することは
できていたので、いずれ注文しようかと思っていました。

改めて読み直すと、いわゆるサラリーマン的というか、
出世術っぽくもありますけど。それでも、技術系で
あっても通用する仕事の進め方だと思います。

ちなみに佐々木氏のサイト:http://sasakitsuneo.jp/

ああ、もちろん、自分がこのルールで全面的にバリバリ
仕事するとかいうことはないです。

--

しかし、コードを書き写して本文書き写さないって、
本末転倒な気もするんだけど (笑)。

半分冗談だけど残り半分は本気だよ?

本家Permlink


2010年02月16日

http://blog.practical-scheme.net/shiro/20100215-when-you-should-use-lisp-2

でも、そうだとすると、自分には関係のない世界に
なっちゃいますね (笑)。『極めて複雑な処理が必要で』
っていうのは、自分の能力的にないでしょうから。

それはそれとして、逆に、1つの言語ですべてを済ます
ことをあきらめたら、選択肢がかなり広がるともいえるん
じゃないでしょうか。Gaucheにしても、Rubyにしても、
C言語との親和性を重視してると思いますし。Clojureに
しても、Javaをスッ飛ばしてJNIで書くこともできるん
じゃないでしょうか。

--

『プログラミング Clojure』の不在票がポストに入って
ました。といっても、英語のPDFを買って、もう結構読み
進めちゃってるんですけど。

JRubyでSwing使うかなぁといろいろ試してるうちに、
そういえばClojureってどんなもんかなぁと思って。

対JVMという点では、Clojureのほうがいいですね。
JRubyは、やっぱりRubyになることに一生懸命で、対JVMに
最適化されてるわけじゃありませんから。そういう意味で、
lazy sequenceであるとか、software transactional memory
だとかを抜きにしても、便利そうだなぁと。自分には
カッコアレルギーはありませんし。

一方、JRubyのいいところは、Javaのコードを移植しやすい
ところです。JRuby向けに書き直す必要があることもあるん
ですけど、頻度は少ないです。

Clojureの話に戻りますけど、自分はArcのことをよく
知らないんですけど、Lispってまだまだ便利になれると
いうか、書く労力を減らせるもんなんだなぁと思いました。
mapがそのまま関数になったり、keyがそのまま関数に
なったりとかは、自分にとってはかなりツボでした。

--

しかし、JRubyもClojureも:

import javax.swing.*;

相当の機能、入れてくんないかな。マジメンドーなんだけど。
なんのためにLL使ってるのか腹立ってくる。

Swing TutorialをJRubyに移した中だと:

import java.awt.BorderLayout
import java.awt.Cursor
import java.awt.Dimension
import java.awt.Font
import java.awt.GridBagConstraints
import java.awt.GridBagLayout
import java.awt.GridLayout
import java.awt.Insets
import java.awt.Toolkit
import java.awt.event.ActionListener
import java.io.IOException
import java.lang.ClassLoader
import java.lang.Runnable
import java.net.URL
import java.util.Calendar
import javax.swing.BorderFactory
import javax.swing.ImageIcon
import javax.swing.JButton
import javax.swing.JEditorPane
import javax.swing.JFormattedTextField
import javax.swing.JFrame
import javax.swing.JLabel
import javax.swing.JPanel
import javax.swing.JPasswordField
import javax.swing.JTextArea
import javax.swing.JTextField
import javax.swing.JTextPane
import javax.swing.JScrollPane
import javax.swing.JSplitPane
import javax.swing.UIManager
import javax.swing.text.BadLocationException
import javax.swing.text.StyleConstants
import javax.swing.text.StyleContext

っていうのがある。

TextSamplerDemo.rb

--

さっきのは怪しかったので訂正:

include Java

import javax.swing.SwingUtilities
import javax.swing.JFrame
import javax.swing.JPanel
import javax.swing.BorderFactory
import java.awt.Color
import java.awt.Dimension
import java.awt.Graphics
import java.awt.Point

class SwingPaintDemo3
  include java.lang.Runnable

  def createAndShowGUI
    f = JFrame.new
    f.setDefaultCloseOperation(JFrame::EXIT_ON_CLOSE)
    f.add(MyPanel.new)
    f.pack
    f.setVisible(true)
  end

  def run
    createAndShowGUI
  end
end

class MyPanel < JPanel
  def initialize
    super()
    setBorder(BorderFactory.createLineBorder(Color::black))
  end

  def getPreferredSize
    return Dimension.new(250, 200)
  end

  def paintComponent(g)
    super(g)
    p1 = Point.new(10, 10)
    p2 = Point.new(100, 100)
    p3 = calc_line(p1, p2, 50)
    p p3.toString
    g.drawLine(p1.x, p1.y, p3.x, p3.y)

    q1 = Point.new(100, 100)
    q2 = Point.new(10, 10)
    q3 = calc_line(q1, q2, 50)
    p q3.toString
    g.drawLine(q1.x, q1.y, q3.x, q3.y)
  end

  def calc_line(p1, p2, dist)
    w = p2.x - p1.x
    h = p2.y - p1.y
    rad = Math.atan2(h, w)
    x = dist * Math.cos(rad)
    y = dist * Math.sin(rad)
    return Point.new(p1.x + x.to_i, p1.y + y.to_i)
  end
end

SwingUtilities.invokeLater(SwingPaintDemo3.new)

本家Permlink


2010年02月15日

http://tabesugi.net/memo/cur/cur.html#031943

  1. 問題を発見する能力
  2. 問題を分析する能力 
  3. 問題を切り捨てる能力 

なるほどと思う反面、どこか足りない気もします。

「問題を分析する」というのがどこまでを指すのかにも
よるんですけど。

自分としては、「問題を分析する」っていうのは、まだ
現実世界の話というイメージがあります。たとえば、
運賃表を例にとると、距離や曜日によって運賃が変動する
ものだとすると、そうした変動のルールを整理すると
いうのが分析だといった感じです。

そんなイメージを持っているものだから、自分の中では、
やっぱり現実世界をコンピュータ上の世界に移す作業が
あると思ってます。

ある現実世界のルールみたいなものをコンピュータの
世界に移すとき、その実装はいくつも考えられると思う
んですよね。それこそOOPとか関数型とか。で、どういう
実装を選ぶかは人によって様々でしょうけど、やっぱり
どの実装を選んだとしても、それぞれに検討しなきゃ
いけない事柄があるでしょう。当然、実装どうしで優劣が
出ることもあるでしょう。

で、いくらよく分析できたとしても、やっぱり実用に
ならないと意味がないと自分は思うわけです。

本家Permlink


2010年02月10日

(setq clojure-inferior-lisp-program
      "java -classpath .;c:/clojure-1.1.0/clojure.jar;c:/clojure-contrib/clojure-contrib.jar clojure.main")
(autoload 'clojure-mode "clojure-mode" 
  "Mode for editing clojure source files" t)
(setq auto-mode-alist
      (append '(("\\.clj$" . clojure-mode)) auto-mode-alist))

本家Permlink


2010年02月08日

風邪で寝込む。

Swing TutorialをJRubyに移すのもあらかた終わっててヒマ。

Swing TutorialをJavaScriptに移すことを思いつく。

JavaクラスをJavaScriptで拡張するやり方がわからない。

JavaScriptをあきらめてKawaを試す。

Kawaを調べてたらClojureが引っかかる。

amazon.co.jpで本を注文したけど、売れてるみたいで届くのが14日といわれる。

仕方ないのでPragmatic BookshelfでPDFを買う。

そんな好奇心駆動の週末でした。まだ風邪は治ってません。

本家Permlink


Copyright © 1905 tko at jitu.org

バカが征く on Rails