CyanでCLのfind系関数っぽいものを生成するマクロ
定義に使うだけなのでselfの退避先以外の(必要なかった)シンボルは決め打ち。捕捉とかも大丈夫、だと思うけどどうだろう?
引数の取り方もアレだけど定義に使うだけなので以下略
def(Object.equal)^(obj): (.parent == obj.parent) && (self == obj) mac(make_finder)^(name, cond, result, &opt acc0, acc_next, fin): func := Function.new($(arg),`{ let(rec)^(&opt self = self, acc = ?acc0): if (.null?()): ?fin else: if (?cond): ?result else: rec(self.cdr(), ?acc_next) }) Porter.new('def, &(Messenger.new('List, name), func)) make_finder(find, arg.equal(.car()), .car()) make_finder(find_if, arg(.car()), .car()) make_finder(member, arg.equal(.car()), self) make_finder(member_if, arg(.car()), self) make_finder(position, arg.equal(.car()), acc, 0, acc + 1) make_finder(position_if, arg(.car()), acc, 0, acc + 1) make_finder(remove, arg.equal(.car()), rec(.cdr(), acc), [], acc.append([.car()]), acc) make_finder(remove_if, arg(.car()),rec(.cdr(),acc), [], acc.append([.car()]), acc) make_finder(some, arg(.car()), true, [], [], false) make_finder(every, !arg(.car()), false, [], [], true) make_finder(notevery, !arg(.car()), true, [], [], false) make_finder(notany, arg(.car()), false, [], [], true) #| def(List.every)^(f): !.some(complement(f)) def(List.notevery)^(f): .some(complement(f)) def(List.notany)^(f): !.some(f) |# mac(_?)^(exp): say "#?= " + exp.to_s() `let^(&opt result = (?exp)): say "#?- " + result.to_s() result def(findtest)^: x := iota(10) _? x _? x.find(4) _? x.find_if^(n): n > 8 _? x.member(5) _? x.member_if^(n){ n * n > 10 } _? x.position(6) _? x.position_if^(n){n.rem(2) == 1} [^(n){ n < 10}, ^(n){ n < 0 }, ^(n){ n.rem(2) == 0 }].foreach^(f): say([f, x.some(f), x.every(f), x.notevery(f), x.notany(f)].to_s()) _? x.remove(5) _? x.remove_if^(n){ n.rem(3) == 0 }
named let便利。CLではpregexpのソースにあったrecurっていうマクロをちょこちょこ使ってたりしたんだけれども。
てすてす
cyan> findtest() #?= x #?- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] #?= x.find(4) #?- 4 #?= x.find_if(^(n){ n.(>)(8) }) #?- 9 #?= x.member(5) #?- [5, 6, 7, 8, 9] #?= x.member_if(^(n){ n.(*)(n).(>)(10) }) #?- [4, 5, 6, 7, 8, 9] #?= x.position(6) #?- 6 #?= x.position_if(^(n){ n.rem(2).(==)(1) }) #?- 1 [^(n){ n.(<)(10) }, true, true, false, false] [^(n){ n.(<)(0) }, false, false, true, true] [^(n){ n.rem(2).(==)(0) }, true, false, true, false] #?= x.remove(5) #?- [0, 1, 2, 3, 4, 6, 7, 8, 9] #?= x.remove_if(^(n){ n.rem(3).(==)(0) }) #?- [1, 2, 4, 5, 7, 8] => [1, 2, 4, 5, 7, 8]
ネタ
cyan> make_finder(len, [], [], arg, acc + 1, acc) => ^(self, arg){ let(rec, ^(&opt self = self, acc = arg){ if(self.null?(), { acc }, :else { if([], { [] }, :else { rec(self.cdr(), acc.(+)(1)) }) }) }) } cyan> [1,2,3].len(0) => 3 cyan> make_finder(rev, [], [], arg, [.car() | acc], acc) => ^(self, arg){ let(rec, ^(&opt self = self, acc = arg){ if(self.null?(), { acc }, :else { if([], { [] }, :else { rec(self.cdr(), [self.car() | acc]) }) }) }) } cyan> [1,2,3].rev([]) => [3, 2, 1]
ついでにmap系。
mac(make_mapper)^(name, args_form, acc_next): func := Function.new($(fun), `{ let(rec)^(&opt self = self, acc): args := ?args_form if (.some^(_){_.null?()}): acc else: rec(.map^(_){_.cdr()}, ?acc_next) }) Porter.new('def, &(Messenger.new('List, name), func)) make_mapper(mapc, .map^(a){ a.car() }, fun(*args)) make_mapper(mapcar, .map^(a){ a.car() }, acc.append([fun(*args)])) make_mapper(mapcan, .map^(a){ a.car() }, acc.append(fun(*args))) make_mapper(mapl, self, fun(*args)) make_mapper(maplist, self, acc.append([fun(*args)])) make_mapper(mapcon, self, acc.append(fun(*args))) def(maptest)^: x := [iota(5), iota(5,5)] _? x.mapc^(a,b): say(a * b) _? x.mapcar^(a,b): [a, b] _? x.mapcan^(a,b): [a, b] _? x.mapl^(a,b): say(a.append(b).foldl(0)^(c,d){ c + d }) _? x.maplist^(a,b): a.append(b) _? x.mapcon^(a,b): a.append(b)
てst
cyan> maptest() #?= x.mapc(^(a, b){ say(a.(*)(b)) }) 0 6 14 24 36 #?- 36 #?= x.mapcar(^(a, b){ [a, b] }) #?- [[0, 5], [1, 6], [2, 7], [3, 8], [4, 9]] #?= x.mapcan(^(a, b){ [a, b] }) #?- [0, 5, 1, 6, 2, 7, 3, 8, 4, 9] #?= x.mapl(^(a, b){ say(a.append(b).foldl(0, ^(c, d){ c.(+)(d) })) }) 45 40 33 24 13 #?- 13 #?= x.maplist(^(a, b){ a.append(b) }) #?- [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 6, 7, 8, 9], [2, 3, 4, 7, 8, 9], [3, 4, 8, 9], [4, 9]] #?= x.mapcon(^(a, b){ a.append(b) }) #?- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 6, 7, 8, 9, 2, 3, 4, 7, 8, 9, 3, 4, 8, 9, 4, 9] => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 6, 7, 8, 9, 2, 3, 4, 7, 8, 9, 3, 4, 8, 9, 4, 9]
mapc, maplは元のリストを返すのではなく、mapfっぽく最後の結果を返すようにしてみた。
mapfはまたいつか。