use JavaFX from Jython

I love Python, even on JVM! So, I decided to use JavaFX from Jython.

This article is a 20th day of JavaFX Advent Calendar 2012

I started translating Java code on this article into Jython.

Setting up Environment

We need JavaFX SDK and Jython which can use it. A following sequence is actual processes I went through.

To obtain JavaFX developing environment, I installed JavaFX for Java SE 7.

Following this instruction, I made Java 7 as a default JDK.

$ sudo mv /System/Library/Java/JavaVirtualMachines/1.6.0.jdk /System/Library/Java/JavaVirtualMachines/1.6.0.jdk.bak
$ sudo ln -s /Library/Java/JavaVirtualMachines/1.7.0.jdk /System/Library/Java/JavaVirtualMachines/1.6.0.jdk
$ java -version
java version "1.7.0_04"
Java(TM) SE Runtime Environment (build 1.7.0_04-b21)
Java HotSpot(TM) 64-Bit Server VM (build 23.0-b21, mixed mode)

Next I compiled Jython with Java 7.

$ hg clone https://bitbucket.org/jython/jython
$ cd jython
$ ant
$ ls dist/bin/jython

The result jython executable exists at dist/bin/jython. When I compiled, the Mercurial changeset ID is 6898:2ccd73a00a86 and Jython version is 2.7.0a2+.

Now, all had been set up.

Hello, World!

Since ...

Scalaz の Functor trait を初心者が実装してみた

Scalaz Advent Calendar の 10 日目の記事として書いています.

前回の記事 では Functor の構造について数学の定義を対比させながら書きました. 今日は Scalaz を使ったプログラムを書いて Functor の実装をしてみましょう.

準備

今回の実装をするために sbt で管理している Scala プロジェクトを作成しました. 同じ環境を作成して色々触ってみると楽しいと思います. 実際, 私は自分で実装してみて Functor の使い方がより分かるようになりました.

私は以下の環境で作業しました. (scala, scalaz は sbt で取得するので, sbt のバージョンさえ合っていれば同じ作業ができるはずです)

sbt 0.12.1
scala 2.10.0-M7
scalaz 7.0.0-M3
Giter8 0.4.5

Giter8 についてはこちらを参照してください. http://blog.twiwt.org/e/f12c0f

前置き

説明を簡単にするために implicit なものは使っていません. 対象を函手で写すときには, implicit conversion を使うと綺麗に書けるのですが, 今回はそこが本題ではないので敢えて使っていません.

今回は以下のページを参考にしました.

環境準備

g8 typesafehub/scala-sbt コマンドを実行して, パッケージ名など適宜答えていきましょう. scala のバージョンを聞かれたら 2.10.0-M7 としておいてください.

<project_root>/project/<project_name>.scala に sbt の設定を追加して, scalaz が利用できるようにします.

resolvers += "Typesafe Snapshots" at "http://repo.typesafe.com/typesafe/snapshots/",

libraryDependencies ++= Seq(
  "org.scalaz" % "scalaz-core" % "7.0.0-M3" cross CrossVersion.full
),

scalacOptions += "-feature",

initialCommands in console := "import scalaz._, Scalaz._"

実際のファイルは https://bitbucket.org/cocoatomo/scalazsample/src/e5efd3d7b750/project/ScalazsampleBuild.scala?at=default を見てください.

次に <project_root>/src/main/scala/<package_hierarchy>/なんとか.scala に以下の import 文を追加します.

import scalaz.Functor

ソースコードは https://bitbucket.org/cocoatomo/scalazsample/src/a451998f4f2fa9ab09771622a333e9dd9fbe64b9/src/main/scala/net/elliptium/Scalazsample.scala?at=default を見てください.

そして最後にコンソールに戻って sbt run コマンドを実行すると, scalaz-core の取得が行われ, プログラムが動きます. g8 コマンドの引数に typesafehub/scala-sbt を指定してプロジェクトを作成した場合, "Hello, <project_name>" メッセージが出力されるだけのプログラムになっているはずです.

作成する Functor

今回作成する Functor は Important という名前にします. 普通の「クラスの圏」から「重要なクラスの圏」への函手というイメージになります. 今回持ち上げる射の例として length というものを選びます. 図式を書くと以下のようになります.

              lift(length)
Important[String] → Important[Int]
       ↑                ↑
       ↑                ↑
       ↑                ↑
     String       →     Int
                length

length: String => Int 函数は名前の通り「文字列の長さ」を返すものです. Important という Functor は「2重にする」函手です. 実体は Tuple2 に似た case class で, toString をちょっとイジってあります. これはソースコードを見た方が理解が早いでしょう.

実装

Important

これが Important[T] の実装です.

case class Important[T](val value: T) extends Product2[T, T] {

  def _1: T = value
  def _2: T = value

  override def toString: String = value.toString + ", " + value.toString

}

このクラスのコンストラクタで「普通のクラス T 」を「重要なクラス Important[T] 」に持ち上げています. 図式の以下の矢印にあたります.

Important[String]    Important[Int]
       ↑                ↑
       ↑                ↑
       ↑                ↑
     String ...

Scalaz の Functor.scala を初心者が読んでみた

Scalaz Advent Calendar の 6 日目の記事として書いています.

準備

今回解説するソースコードは scalaz/Functor.scala です.

scalaz-seven ブランチのものであることに注意してください.

前置き

数学 (代数) は一応やってはいたものの, Scala や Scalaz のことを全然分からない状態からこの記事を書いています. そんな人間が Scalaz を読んだらどう見えるか? という実験記録のようなものがこの記事です.

圏論については「圏論の基礎」を参照しています. 用語などはそちらに倣いました.

数学の函手とは

最初にざっと圏論の概念の定義を並べておきます.

圏 (category) の定義

  • 圏とは対象 (object) と対象の間の射 (arrow) の集まり

    • f はある対象 a とある対象 b を結び付けるもの

      この射は方向を持っているので f: a → b のように表記することが多いです

      この af のドメイン (domain, source), bf のコドメイン (codomain, target) と言います

  • 各対象 c には id c という c から c への射 (恒等射, identity) が存在する

  • f: a → b, g: b → c があったとき, それらをつないだ合成射 (composite) g・f: a → c も存在する

    • 恒等射 id c: c → c と合成の関係は以下の通り

      • f: b → c, g: c → d としたとき (id c)・f = f, g・(id c) = g

        つまり恒等射は合成 (composition) 演算の両側単位元です

    • 複数の合成がつながっている場合合成の順序は問わない

      f: a → b, g: b → c, h: c → d があったとき, (h・g)・f = h・(g・f)

      いわゆる結合則 (associative law) です

つまり圏とは群と群の間の準同型の集まり, のようなものです. この喩えでは, 対象が群という1つの集合なのですが, 圏論では群の元1つ1つについて直接扱わない流儀を採ります.

圏を図で書くと, 圏は対象をノードとし, 射をエッジとする有向グラフになります. これを図式 (diagram) とかと呼んで, 圏の説明で使ったりします.

函手 (functor) の定義

この対象と射を含む圏どうしの間にも対応付け (函手, functor) を考えることができます. 射が対象どうしの対応付けだったのに対し, この函手は圏どうしの対応付けになっていて 1 段上のメタなものになっています.

  • 函手とは圏と圏の間の対応付けで, 対象を対象に, 射を射に対応付ける

    型を考えると対象を写すものと, 射を写すものは別の関数になるのですが, 同じ記号で書いても混ざることは無いので同じ記号を援用したりします

    • 函手 T が写した対象と射の関係は以下の通り

      • T(id c) = id Tc

        恒等射を恒等射に写します

      • T(f・g) = T(f)・T(g)

        合成を保ちます

この函手を大雑把に説明すると, 圏の中にある図式を別の圏に写すものです.

Scalaz の Functor とは

ここまでを踏まえて Scalaz の Functor が数学の函手になっているのか見ていきましょう.

実装

まず Functor の先頭部分は以下のようになっています.

trait Functor[F[_]]  { self =>
  ////

  /** Lift `f` into `F` and apply to `F[A]`. */
  def map[A, B](fa: F[A])(f: A => B): F[B]

  // derived functions
  ...

F という Functor を宣言し, map というメソッドの型が定義されています.

他のメソッドは Functor#map メソッドを使って実装されているので, 最低限 Functor#map だけ実装すれば良さそうです. (このあたりはまた後日追い掛けます)

数学の定義と対比して

Scalaz の Functor はいったいどんな函手なのかを見てみましょう.

Functor#map の型を見てみると以下のようになっています.

/** Lift `f` into `F` and apply to `F[A]`. */
def map[A, B](fa: F[A])(f: A => B): F[B]

これから map メソッドは fa: F[A]f: A => B を受け取って, F[B] 型のインスタンスを返すのが分かります. 意図としては, f という関数を持ち上げて fa に適用しています.

図式として書くと以下のようになります.

F[A] → F[B]
 ↑      ↑
 A   →  B

函手のドメインである圏には AB が対象として存在し, f が射として存在しています. 下の段の矢印が射 f です.

A → B
  f

対象 A, B をそれぞれ持ち上げているのが型パラメータを 1 つだけ受け取る型クラス F です.

  F[A]   F[B]
F ↑    F ↑
  A ...

注釈器は何をしているのか? - PyPy Advent Calendar 2011

この記事は PyPy Advent Calendar 2011 の17日目の記事として書いています. 2周目ってけっこう速く来るんですね. 執筆時刻は気にしないように.

何を書くのか?

PyPy Toolchain には「注釈器 (annotator)」というものが含まれており, こいつは RPython に出てくる変数について, そのメタ情報である「注釈 (annotation)」を与えていきます.

この注釈器の具体的な動きの説明を書いていきます. 途中で力尽きる予定なので, その続きは後日書きます(エ

元ネタ

資料としては The Annotation Pass から参照されている Compiling Dynamic Language Implementations (←PDF です) という論文の §6 Annotator を使っています. 実質この記事は, §6の要約になっています.

この論文は 2005 年のものですが, 全体像を掴むのに良さそうなので選びました.

注釈とは

注釈というのは結局は型 (ある値の集合) なんだけど, Python の方の型とごっちゃになって面倒なので, 敢えて注釈という用語を使っています. 注釈が常に Python の型と一致しているわけではないし, そうなる必然性もありません. Python に新しい型システムを導入していると思ってください.

注釈付け

Python では初期化された瞬間でしか変数の型が分からないことが多いです. なので, 実行順序に沿って前の方から処理を追っていかねばなりません.

注釈付けの処理は本質的には型推論なのですが, Hindly-Milner のように前後に移動しながら型推論を行うことはできないので, それに比べると安直 (naive) な方法です.

ループとかプロシージャ呼び出しとかがあると変数の注釈がより緩い (general) 注釈に変更されることがあるのですが, その場合は再度最初から計算し直して, 注釈がこれ以上一般化 (generalize) されない状態にまで持っていきます.

注釈の種類

注釈の種類には, 型としてお馴染のものとやや Python では聞き慣れないものがあります.

  • Bot, Top: Bottom と Top. Java で言う「暗黙的にある null のクラス」と「Object」です.
  • Int, NonNegInt, Bool: Bool は特殊な Int として定義されています. (たぶん 0 と 1)
  • Str, Char: Char は長さ1の String です.
  • List(v): v はリストの要素のようです.
  • Pbc(set): set は実行時に定義される定数の有限集合だそうだ. function とか class とか method という callable もここに入っています.
  • None: Python の None です.

ここではリストに載せなかったけど, NullableStr みたいな注釈や dict, tuple, float, unicode point, iterator などなどの注釈もあるんだけど発想はストレートなものなので説明省略します.

そしてこれら注釈の間には包含関係があり, その関係による束 (lattice) を構成します. Top が一番上に来て最も緩い型を表し, Bot が一番下に来て最も狭い型 (=どんな値も取りようの無い型) を表します. これについては PDF の Figure 1 と 2 を見てください.

注釈器の目的

以下のように記号を置きます.

  • A: さっき出てきた注釈が成す束
  • V: 全ての変数の集合
  • E: 変数どうしの同値関係
  • b: 関数 V -> A

A, V は分かりやすいと思います. E は, 2つの変数が同じ値を指しているかどうかの情報を蓄えている, と捉えてください. b は, ある変数がどの注釈に属するのか (ある変数にどの注釈を付けるべきか) を表している, と捉えてください.

この記号を使って状態 (state) とその間の関係 (generality) を説明します.

状態というのは関数 b: V -> A と V 上の同値関係 E の組 (b, E) で, 要は注釈情報の集まりです. ある状態 (b', E') が状態 (b, E) より一般的 (general) というのは, ∀v ∈ V, b'(v) ≧ b(v) かつ E' ⊃ E であることを言います. (A 上の関係 ≧ は注釈の包含関係 ⊃ に等しい.) 言葉で説明すると, 全ての変数について同じかより広い注釈を付け, 同値関係にある変数の組が同じか増えている状況を言います.

最も一般的な状態 (b_max, E_max) というのは, ∀v ∈ V, b_min(v) = Top, E_max = {(v, v') | v, v' ∈ V} のことです. つまり, 型に関して何にも情報がありません. 逆に最も一般的でない状態 (b_min, E_min) というのは, ∀v ∈ V, b_min(v) = Bot, E_min = {(v, v) | v ∈ V} のことです. つまり, 全ての変数が値を取り得ないというへんてこりんな状況です.

ここまでで準備した言葉によって, 注釈器の目的を以下のように書くことができます.

解析対象のプログラムに対して, 最も一般的でない (狭い) 状態を求める.

語弊を恐れずに言うと, それぞれの変数が取り得る型の中で最も狭いものを求める, ということです.

まとめ

突然まとめに入ります.

PDF の 6.1 から 6.4 あたりを眺めて軽くまとめただけですが, 色々細かいところや 6.4 の後半以降を省いています. これがブログ記事だということもありますし, まだ自分がちゃんと読めてないという理由もあります. 元の論文が 2005 年に発表されたものなので, それ以降の情報なども加えつつ, これの続きに関してどこかでちゃんと説明したいと思っています.

次は Masahito さん です. よろしくお願いします.

それでは.

Let's translate.py! - PyPy Advent Calendar 2011

お前, 誰よ?

改めまして cocoatomo と申します. 技術的な話はこの ID とペンギンアイコンで通しているので, 他の場所で cocoatomo と見たらきっと私です.

プログラムの静的解析に興味があり, PyPy の処理過程のうちでも前半にある Control Flow Graph への変換および注釈付け (メタデータの付与) を勉強中です. 正直, 後半の JIT とかはあんま興味無いです. そこは @chlere さんという優秀な方がいるので, そちらにお任せして色々教えてもらっています.

今回の記事は PyPy Advent Calendar 2011 の4日目として書いています.

翻訳とは?

さて, 表題にある translate.py とは何ぞや? 翻訳? 何を翻訳? と思われたと思います. 実は私にとって「翻訳」は2重の意味があって, PyPy の処理過程の一部である translate.py のことと, 私が行っている PyPy の公式ドキュメントの翻訳です. (しかも translation.html の翻訳なので, 「翻訳」の翻訳です.)

translate.py は ${PYPY_HOME}/pypy/translator/goal/translate.py にあります. 私の翻訳は PyPy - RPython toolchain — PyPy 1.6 documentation に置いてあります. まだ翻訳は完了していませんが, これを読んでいけば PyPy がどんな処理を行っているかのイメージが付くでしょう.

PyPy が行っていることを大雑把に説明すると, RPython という Python っぽい言語で書かれたプログラムを変換して, 型などの情報を付加して, そこから色々な言語のソースコードを出力します. この変換のことを翻訳と名前を付けたようです.

translatorshell.py

さて難しい話は置いておいて, まずは翻訳して遊んでみましょう.

環境

私は楽をするためこんな環境で作業しています.

  • Mac OS X 10.7 Lion (gcc は llvm-gcc)
  • PyPy のソース一式を bitbucket から取得
  • homebrew で pypy をインストール

モジュールまわりで面倒が無いように homebrew に pypy をビルドしてもらって使っています.

翻訳遊び

(flow モデル のあたりを参照しながら読み進めると良いかもしれません.)

$ cd $PYPY_HOME/pypy
$ pypy bin/translatorshell.py

と実行すると, なにやらメッセージとともに ``>>>> `` という PyPy のプロンプトが出てきます. Python と違って ">" が4つあるのが特徴です.

System Message: WARNING/2 (<string>, line 46); backlink

Inline literal start-string without end-string.

ここで適当な関数 succ を定義して, 翻訳処理に掛けます.

>>>> def succ(x): return x + 1
>>>> t = Translation(succ)
>>>> t.view()
http://desmond.yfrog.com/Himg615/scaled.php?tn=0&server=615&filename=fxlg.png&xsize=640&ysize=640

何かウィンドウが出てきてフローチャートみたいなものが表示されました. このウィンドウは Pygame のもので, 変換結果が目で見て分かる形で表示されます.

中身は succ が変換されたものなので見れば, まぁ分かるでしょう. ESC キーを押してウィンドウを閉じてください.

今度はこれにメタデータを付加しましょう.

今は succ には数値が来ることを期待しているので, succ の引数 x が int であることを PyPy に教えましょう.

>>>> t.annotate([int])
>>>> t.view()

最初に annotate メソッドを実行すると, とあるモジュールがコンパイルされるようです. gcc-4.0 という実行ファイルが求められるので, 私は

$ ln -s /usr/bin/gcc /usr/bin/gcc-4.0

とやや適当な対応をしました. とりあえずこれで動いているようです.

http://desmond.yfrog.com/Himg859/scaled.php?tn=0&server=859&filename=41917068.png&xsize=640&ysize=640

t.view() と再度フローチャートを表示すると, さっきと少し変わっているところがあります. x_0, v_0, v_1 という文字の色が変わってリンクになっています. 真ん中の四角の中に inputargs: x_0 とあるので, きっと succ(x) の x のことなのでしょう. クリックしてみます. 何やらメッセージが出ますが SomeInteger という文字列が見付かるでしょうか? これがさっき「succ の引数 x は int である」と教えた結果です. PyPy では "int" という型情報を SomeInteger というクラスで表現しています.

v_0 をクリックするとやはり同じように SomeInteger という文字列を含んだメッセージが出てきます. Backspace を押して最初の画面に戻ってみると, v_0 というのは v_0 = add(x_0, (1)) というものらしいです. 元々のプログラムでは return x + 1 と1つの文で書いていたものが v = x + 1; return v (←注. Python のソースコードとしては正しくない) と2つの文に分割されているようです.

int である x に 1 を加えた結果はもちろん int なのですが, 普通の Python ではこのような推論は行ってくれません. それはそもそも「x が int である」という情報を渡す口が無いからです. (Python3 で関数アノテーション入ったじゃないか, と言われそうですが, あれに推論の機能は無かったはずです. もし間違っていたら是非教えてください.)

PyPy によって int 型だと判明した v_0 を次の四角に渡し, 次の succ__2 という名前の四角で v_1 として受け取られ return されています. もちろん v_1 に来るのは v_0 という int なので v_1 も int 型です. その証拠に v_1 をクリックしてみましょう. v_0 と同じように SomeInteger という文字列がありますね.

蛇足ですが, 元々は同じ v という変数なのに v_0 とか v_1 という名前に分けられているのは 静的単一代入 (SSA) という形式に変換されているからです. この形式では, ある変数への代入は1回しか行えず, 再度代入するときには別の変数に代入しているものと看做します. この形式にしておいた方が何かと処理が楽なので, 変換や最適化の中間表現として採用されます.

さてここまでで succ が PyPy 内部でどう扱われるかを見渡すことができました. 今回は succ という簡単な例でしたが, 是非 for 文や if 文を含む関数をみなさんの手を動かして PyPy で変換してみてください.

まとめ

今回は理論的に掘り下げた話はせず, まずは PyPy に触れてみよう, translation.py で遊んでみよう, という話をしました. 実は別の話を書こうと思って準備をしていたところ, Pygame のウィンドウを出すためにモジュールをコンパイルするところで引っ掛かってしまい, せっかくなのでそこの部分について詳しく書きました.

Advent Calendar の2周目が回ってきたら理論的なところなどを書いてみようと思います.

次の担当は Masahito さん です. よろしくお願いします.

それでは.

Licenses