2008年 05月 13日

Io って頭おかしいなぁ (いい意味で)

curlyBrackets を知った。

Object curlyBrackets := Object getSlot("method")

foo := {
	"aaa" println
}

bar := {a,
	"bbb" println
	a
}

foo

bar(getSlot("foo")) # method は普通に書くと実行されてしまうので getSlot する必要がある。
aaa
bbb
aaa

ちょっと他の言語に近づいた感じ。

もう少し変態的にしてみる

def foo (mes) {
    mes println
}

こういうふうに書けるようにするために def メソッドを定義する

def := {
	name := call message next name
	args := call message next arguments map(i, i name)
	meth := call message next next
	next := meth next

	# cut message chain
	meth setNext(nil)

	# set the method to caller context
	call sender setSlot(name, call sender doMessage(meth))

	# set arguments list
	call sender getSlot(name) setArgumentNames(args)

	# pass to next message
	call message setNext(next)

	# return the method
	call sender getSlot(name)
}
# 引数なしなら仮引数省略可
def hogehoge {
	"hogehoge" println
}

def piyopiyo (mes) {
	mes println
}

# 引数なしなら括弧いらない
hogehoge
hogehoge()

# 引数ありなら括弧必須
piyopiyo("foobar")

Foo := Object clone do (
	def foo (mes) {
		mes println
	}
)

Foo foo("alert")

書いた式がどうコンパイルされたかは (前にも書いたけど) 以下のようすればわかる。

Message fromString("def foo (mes) { mes println }") code println
#=> def foo(mes) curlyBrackets(mes println)

call message は呼びだしもとのメッセージチェイン (def foo(mes) curlyBrackets(mes println)) をさしてる。call message next は今のチェインの次、すなわち foo(mes) curlyBrackets(mes println) で、call message next name で先頭のメッセージの名前がとれる。メッセージを自分でとって doMessage することでメソッドを作って、呼びだしもとのコンテキストにセットする。setNext でメッセージをチェインを切ったり、スキップしたりする。

実際もっと簡単に

def := method(
	ret := Object clone do (
		foo := method(
			self args := call message arguments map(i, i name)
			self
		)

		curlyBrackets := method(
			meth := method() setMessage( call message argAt(0) ) setArgumentNames(args)

			context setSlot("foo", meth)
		)
	)
	ret context := call sender
	ret
)

def foo () {
	"faaa" println
}

foo

とかだと、method_missing 相当がないのでうまくいかない。(これは動くけど、foo 決めうちだからうごいてる)

method_missing に相当するのは forward だった

2007年 10月 21日

Io における演算子拡張

Io は演算子の Map を内部に持っていて、パース時にそれを参照する。

例えば =~ は定義されていないので

Message fromString("\"abc\" =~ \"a.\"") code print
#=> "abc" =~ "a."

となり、これだと =~ というメッセージを定義しても、後ろの文字列 (Sequence) は =~ メッセージの引数とは解釈されない。"abc" =~ と "a." は別の文になるわけです。

しかしながらこれは拡張することができて

OperatorTable addOperator("=~", 7)
Message fromString("\"abc\" =~ \"a.\"") code print
#=> "abc" =~("a.")

ということができる。7 は演算子の優先順で、OperatorTable print すれば登録済みの演算子とその優先順位がわかる。

Operators
  0   ' ( ) . ? @ @@
  1   **
  2   ++ --
  3   % * /
  4   + -
  5   << >>
  6   < <= > >=
  7   != ==
  8   &
  9   ^
  10  |
  11  && and
  12  or ||
  13  ..
  14  %= &= *= += -= -> /= <- <-> <<= >>= ^= |=
  15  return
  16  ,

Assign Operators
  ::= newSlot
  :=  setSlot
  =   updateSlot

To add a new operator: OperatorTable addOperator("+", 4) and implement the + message.
To add a new assign operator: OperatorTable addAssignOperator("=", "updateSlot") and implement the updateSlot message.

ところで若干のハマりどころなのは、

Object =~ := method(s,
	call message print
)
OperatorTable addOperator("=~", 7)

"abc" =~ "a."

とやっても、"abc" =~ "a." をパースする時点では addOperator はまだ評価されていないので、演算子にはならない。doString とかでこのあとにパースされるようにしないといけない。実際つかうとするとファイルをわけて doFile みたいになると思う。

Io かっけー

2007年 10月 20日

Io squareBrackets ちんこ演算子その他の雑多メモ

[1, 2, 3] は squareBrackets(1, 2, 3) と同じっぽいのだけど、デフォルトだと何にも割りあてられてない。

Io> squareBrackets := getSlot("list")
==> # io/A2_Object.io:401
method(
    call message argsEvaluatedIn(call sender)
)
Io> [1, 2, 3]
==> list(1, 2, 3)
Io> list(1, 2, 3)[0]

  Exception: List does not respond to 'squareBrackets'
  ---------
  List squareBrackets                  Command Line 1

Io> List squareBrackets := List getSlot("at")
==> List_at()
Io> list(1, 2, 3)[0]
==> 1
Io> [1, 2, 3][1]
==> 2

Io ではいろいろメッセージセンドになってる (てきと)。:= は setSlot の言いかえである。すなわち

Io> setSlot = method( "This is penis operator.\n" print )
==> method(
    "This is penis operator.\n" print
)
Io> seme := uke
This is penis operator.
==> This is penis operator.

Io> seme

  Exception: Object does not respond to 'seme'
  ---------
  Object seme                          Command Line 1

ということができる。もちろん上書きしているので変数への代入 (に見えるスロットへのセット) は行なわれない。ついでに uke も評価されないため、エラーが発生しない。仮引数を書かなければ暗黙的な評価はされない。

評価されるケース (仮引数を書いた場合)

Io> setSlot = method(a, b, "This is penis operator. Uke: #{b}\n" interpolate print )
==> method(a, b, 
    "This is penis operator. Uke: #{b}\n" interpolate print
)
Io> seme := "aaa"
This is penis operator. Uke: aaa
==> This is penis operator. Uke: aaa

Io> seme := uke

  Exception: Object does not respond to 'uke'
  ---------
  Object uke                           Command Line 1
  Object setSlot                       Command Line 1

あるいは call evalArgAt(n) で明示的に評価できる。( call sender doMessage(call message argAt(1)) の簡易版 )

Io> setSlot = method(uke := call evalArgAt(1); "This is penis operator. Uke: #{uke}\n" interpolate print )
==> method(
    uke := call evalArgAt(1); "This is penis operator. Uke: #{uke}\n" interpolate print
)
Io> seme := uke

  Exception: Object does not respond to 'uke'
  ---------
  Object uke                           Command Line 1
  Object setSlot                       Command Line 1

Io> seme := "uke"
This is penis operator. Uke: uke
==> This is penis operator. Uke: uke

interpolate というメソッドがでてきたけど、これは #{name} をローカル変数で置換するメソッド (式は書けないっぽい)


ブロックあるいはメソッドは、そのコンテキストに入るときにオブジェクトが一つ割りあてられる。これは JS でいうところの Activation Object (Io でも変数オブジェクトとして使われる) で、やはり直接それをとりだすことはできない?

Io> block( slotNames ) call
==> list("updateSlot", "call", "self")

とやると、上の call evalArgAt(1) で出てきた Call オブジェクトが入った call スロットがあることがわかる。



ちんこ演算子が使える言語なのでおもしろいですね。

2006年 07月 31日

iolanguage

久しぶりに Io でもやってみようか、と思いきや、本家のブログのパーマリンクがエラー吐いてて萎える。

バイナリ

バイナリがいつのリリースだかわからない罠だなぁ。ソースからコンパイルしてみよう。

ソースから

えらーでた。あきらめた。バイナリは 20060214 だった。古
ダイナミックロードってできないのかな。なんか必要なのを全部まとめてビルドしてリンクしてるみたいだけど、やたら make に時間かかる。

IoVM

Full じゃないほうはいけた。っていうか普通にコアじゃない部分でエラーなんだよね。それでバイナリが生成されないのはなんともかんとも。Makefile 修正していらないのオフにしたりないといけないな。

IoServer

コアだけだと Regex が使えなくて役に立たないのでやっぱりちゃんと原因さぐる。エラーでてるのは OpenGL なので binding/OpenGL を rm -r して make。一応バイナリはできた。

うーん

仕組みとかは面白いんだけどなぁ。いまいち LL じゃないよなぁ。オレッテバスゲーができない。っていうか正規表現!!必須ですから!!