iolanguageでリスト内包表記
[*注意*]
このコードは古くなりました。
以下のタイトルまで移動をお願い致します。
http://d.hatena.ne.jp/ottu/20100601/1275342913
ロクに構文チェックなんてしてないけど、squareBracketsを使って
とりあえず「こう書けば動く」的な内包表記を書いてみた。
単純に call message arguments をパースして foreach なソース生成して doString してるだけ。
しかしそのdoString、Lobbyでしか実行できない。
Lobby doString("~~~") //ok test := Object clone; test doString("~~~") //ng!
x が見つからないやらなんやら。
でもエラー後に test println してみると
しっかり x がセットされているという…。
なので仕方無しに Lobby で doString してやってるんだけど、
Lobby に内包表記内で使う要素(Slot)が既にある場合、
上書きによって既存の値が失われるのを避ける為、
一旦別の場所に退避しておいて最後に元に戻す、という回りくどい事をしてます。
原因分かる方、いらっしゃいましたらこっそり教えてください。
以下ソースコード
squareBrackets := method( args := call message arguments result := List clone if( (args size > 1) and (args at(1) code containsSeq(" in ")) ) then ( eachLine := "temp := List clone; " filterLine := "" count := 0 hasMap := Map clone if( call sender hasSlot("temp") ) then( hasMap atPut( "temp", call sender getSlot("temp") ) ) setList := List clone setList append("temp") args foreach( i, arg, if(i==0) then( continue ) if( arg code containsSeq(" in ") ) then ( items := arg code split("in") key := items at(0) strip li := items at(1) strip if( call sender hasSlot(key) ) then( hasMap atPut( key, call sender getSlot(key) ) ) setList append( key ) call sender removeSlot(key) if( call sender hasSlot(li) ) then ( eachLine = eachLine .. call sender getSlot(li) asString .. " foreach( " .. key .. ", " ) else ( eachLine = eachLine .. li .. " foreach( " .. key .. ", " ) count = count+1 ) else ( filterLine = filterLine .. "if( not ".. arg code .. " ) then( continue ); " ) ) mapLine := "temp append( " .. args at(0) code .. " )" repeatCloseBracket := method( count, result := ""; count repeat( result = result .. ")" ) return result ) result = call sender doString( eachLine .. filterLine .. mapLine .. repeatCloseBracket(count) .. " temp" ) setList foreach( key, call sender removeSlot( key ) ) hasMap foreach( key, value, call sender setSlot( key, value) ) ) else ( args foreach(x, result append( call sender doString(x code) ) ) ) return result ) //値の上書きを避けるテスト用 //x := "test1" //y := "test2" //temp := List clone a := [ x*2 , x in list(1,2,3,4,5,6,7,8,9,10), x isOdd ] b := [ x*2, x in list(1,2,3,4,5,6,7,8,9,10), x>5 ] c := [1,2,3,4,5] d := [ x*3, x in c, x isOdd ] e := [ x+y, x in [1,2,3,4,5], y in [6,7,8,9,10], x isOdd, y isEven ] e_ := [ x+y, x in [1,2,3,4,5], x isOdd, y in [6,7,8,9,10], y isEven ] e println e_ println /* 以下と同様 result := List clone [1,2,3,4,5] foreach( x, [6,7,8,9,10] foreach( y, if( not x isOdd ) then( continue ) if( not y isEven ) then( continue ) result append( x+y ) ) ) result println */ f := [ [x,y], x in [ [1,2], [3,4], [5,6], [7,8], [9,10] ] , y in x, y isEven ] f println /* 以下と同様 result := List clone; [ [1,2], [3,4], [5,6], [7,8], [9,10] ] foreach( x, x foreach( y, if( not y isEven ) then( continue ) result append( [x,y] ) ) ) result println */
しかしこれ、filterメソッドが全てforeach群の一番内側で実行される為
無駄にループを実行しなきゃならない。
filterメソッドに "hoge(x)" とか渡された時、"x" を上手くパースする方法がピンと来ないので
どの要素に対してのselectなのか判別出来ない…
これも誰か良いアイデアをお持ちでしたらこっそり教えてください…。