無名関数(PHP, Python, Ruby)
<?php function divGeneric($dir, $f, $arg){ if(!is_dir($dir)) return false; if($hd = opendir($dir)){ while(false !== $file = readdir($hd)){ if($file != "." && $file != ".."){ $f($dir,$file,$arg,$f); } } closedir($hd); } return $arg; } ?>
↑のように指定したディレクトリ以下のエントリを走査しながら、
各エントリに対して、引数で渡された関数を実行する関数をよく使うのだけど、
これと同じようなのをPythonとかRubyでも書いてみた。
以下は、指定したディレクトリ以下のエントリを再帰的に走査しながら、
配列にエントリを追加していくプログラム。
PHP
<?php function divGeneric($dir, $f, $arg){ if(!is_dir($dir)) return false; if($hd = opendir($dir)){ while(false !== $file = readdir($hd)){ if($file != "." && $file != ".."){ $f($dir,$file,$arg,$f); } } closedir($hd); } return $arg; } $f = create_function('$dir,$file,&$array,$f', 'if(is_dir($dir."/".$file)){ $array[] = $dir; $array = divGeneric($dir."/".$file, $f, $array); } else{ $array[] = $dir."/".$file; } '); $ret = divGeneric("/home/bokko/music", $f, array()); var_dump($ret); ?>
Python
#!/usr/bin/python # -*- encoding: utf-8 -*- import os.path; def divGeneric(dir, f, arg): if not os.path.isdir(dir): return False entryList = os.listdir(dir) for entry in entryList: f(dir, entry, arg) return arg; def divDirOrFile(dir, entry, dir_f, file_f, arg, func): if os.path.isdir(dir + "/" + entry): dir_f(dir, entry, arg) arg = divGeneric(dir + "/" + entry, func, arg) else: file_f(dir, entry, arg) return arg func = lambda dir,entry,arg : divDirOrFile(dir, entry, lambda dir,entry,arg : arg.append(dir), lambda dir,entry,arg : arg.append(entry), arg, func) arg = divGeneric("/home/bokko/music", func, []) print arg
Ruby
#!/usr/bin/ruby $KCODE = 'u' def divGeneric(dir, f, arg) if not File.directory?(dir) return false end entries = Dir::entries(dir) entries.delete_at(0) entries.delete_at(0) for entry in entries f.call(dir,entry,arg,f) end return arg end f = lambda{|dir,file,array,f| if File.directory?(dir + "/" + file) array << dir array = divGeneric(dir + "/" + file, f, array) else array << dir + "/" + file end return array } ret = divGeneric("/home/bokko/music", f, []) p ret;
書いてて思ったけど、PHPだと無名関数はcreate_functionに文字列で渡さないといけないし、
Pythonだとlambda式には単一の式しか書けないけど、Rubyの場合はそんなこと気にしないで書ける。
ただ、前にこんなことを書いて、
そもそも、関数を引数にするということは、静的に流れが読めなくなるので、 上流工程とか、形式的なプログラム検証からすると、非常に困る。
というふうに、ある人からお叱りを受けたことを考えると、あんまり長ったらしい処理を
無名関数として引数で渡したりしない方がいいのかもしれない。
そう考えると、Pythonがlambda式に単一の式しか渡せないのは、技術的な問題というよりは、
可読性とかを重視した結果なのかな。
P.S.
現在、また東京にいます。GWの最終日に東京行きの新幹線なんて乗るもんじゃないですね(_ _)。