2008-08-23
■ [ruby] bitclustに関するメモ
Ruby合宿中に聞いとけばよかった…。
ディレクトリ構成はとりあえず
% ls bitclust/ doctree/ db-1_8_7/
みたいにする。
まずDBフォルダを作る。
% ./bitclust/bin/bitclust.rb -d ./db-1_8_7 init version=1.8.7 encoding=euc-jp
encoding=utf8とかしても、入力を自動的にUTF8に変換してくれたりはしないので注意(今のところ)。
次にリファレンスを読み込む。svn upを忘れずにな。
% ruby -I bitclust/lib/ bitclust/bin/bitclust.rb -d ./db-1_8_7/ update --stdlibtree=./doctree/refm/api/src
末尾に「&& echo ^G」(^GはC-v C-g)とかしとくと終わったときにベルが鳴って良い。「&& say 'finished'」でもいいけど(Mac限定)。
んでサーバ起動。
% ./bitclust/standalone.rb --debug --database=db-1_9_7 --port=10081 --baseurl=""
--debugを付けないと^Cで止められないので注意。
ここまではいいんだ。ここまでは。
ツリーの一部分だけ更新したい
えーと
一部分だけやろうとするとOpenSSLあたりのドキュメントでエラーになるんでDB作るところからやり直さんといかんのだが、 リファレンス書くだけならbc-tohtmlで部分的にHTML作ればいい気がしてきた。
Tips
bitclust/theme/default/style.cssで s/33a/3a3/g とかすると、デザインが青から緑になるのでローカルだとわかりやすくなって良い。
■ [haskell] ParsecでS式をパーズしてみた
てか48時間Scheme(via http://kzk9.net/column/haskell_parsec.html)そのままだが。
import Text.ParserCombinators.Parsec data Value = IntValue Int | StrValue String | ListValue [Value] deriving (Eq, Show) parseSexp :: Parser Value parseSexp = parseAtom <|> parseList parseAtom :: Parser Value parseAtom = parseInt <|> parseStr parseInt :: Parser Value parseInt = do s <- many1 digit return $ IntValue (read s) parseStr :: Parser Value parseStr = do char '"' x <- many stringParts char '"' return $ StrValue $ concat x where stringParts :: Parser String stringParts = do c1 <- char '\\' c2 <- anyChar return $ c1:[c2] <|> do c <- try $ noneOf "\"" return $ [c] parseList :: Parser Value parseList = do char '(' ls <- sepBy parseSexp (skipMany1 space) char ')' return $ ListValue ls main = print $ parse parseSexp "" "(\"1\" (2) 3)"
値をValueで包まんといかんのが嫌なんだが、なんとかならんかなぁ。
IntとStringだけでよければ型クラス?でなんとかなりそうな気がするが、それらのリスト(とリストのリストとか)をどうしたらいいのかわからん。
■ [ruby] Rubyライブラリのサンプルコードを書くときのTips
Rubyのライブラリは大抵、
bin/ (あれば) lib/foo.rb lib/foo/bar.rb test/test_foo.rb example/baz.rb
みたいになるわけだが、example/baz.rbからlib/foo.rbをrequireするにはどうすればいいか?という問題がある。
もちろん、インストールしてしまえば
require 'foo'
でいいわけだが、開発中はそういうわけにもいかない。
「サンプルコードはトップレベルで実行してね」(または、example以下で実行してね)と決めてしまえば、
require 'lib/foo'
とか
require '../lib/foo'
でrequireできるが、これだと決められたディレクトリで実行しないとLoadErrorになってしまう。
そこで、example/baz.rbの最初に以下のように書いておくと、どこから実行しても require 'foo' でいけるようになる。
$LOAD_PATH << File.expand_path("../lib", File.dirname(__FILE__))
何をしているかというと、__FILE__で自分自身(つまりexample/baz.rb)のパスを取得して、baz.rbのある ディレクトリから ../lib を相対的にたどり、requireがライブラリを探す対象として登録している。
(8/26追記: 場合によっては、$LOAD_PATH << より $LOAD_PATH.unshift の方が良いかも。<<は末尾に追加するので、fooというライブラリが既にインストールされてたりするとそっちを読みこんでしまう。)
ちなみにこのTipsはサンプルコードだけでなく、ユニットテストにも使える。
$LOAD_PATH << File.expand_path("../lib", File.dirname(__FILE__)) require 'rspec' require 'foo'
とかね。
■ [haskell] HaskellでS式のライタを書きたいんですけど
とりあえず IntとStringと[a]をSexpValueのインスタンスにしようとしたんですけど、String(つまり[Char])と[a]がバッティングして動いてくれません(><)
{-# OPTIONS_GHC -XTypeSynonymInstances #-} {-# OPTIONS_GHC -XFlexibleInstances #-} {-# OPTIONS_GHC -XFlexibleContexts #-} import Data.List takeChars :: String -> [Int] -> [String] takeChars str ns = map (\n -> [str !! n]) ns class SexpValue a where toSexp :: (SexpValue a) => a -> String instance SexpValue Int where toSexp n = show n instance SexpValue String where toSexp s = show s instance SexpValue a => SexpValue [a] where toSexp ls = "(" ++ (concat $ intersperse "," (map toSexp ls)) ++ ")" main = putStr $ toSexp $ takeChars "abcde" [1,3]
どうしたらいいんだろう。Showとかはどうやってるのかな。
実行時に -I オプション付け足すのでは駄目なんでしょうか。
http://haskell.org/ghc/docs/latest/html/libraries/base/src/GHC-Show.html<br>Show クラスの中に showList というメソッドが用意してあって、デフォルトでは各要素を [ , , ] で括るようになっているけど、instance Show Char の中でこれを書き変えてありますね。<br>instance Show a => Show [a] の中で showsPrec が a型の showList 使って実装されているので、特定の型のリストに対して特別な挙動をさせることが可能になるという仕組みのようです。トリッキーですね。
-XOverlappingInstances でどうでしょう。<br>http://www.kotha.net/ghc_users_guide_ja/type-class-extensions.html#instance-overlap
星一さん:<br>ああ、その手がありましたね。確かに。<br>その場合もディレクトリを意識しないといけないので、(面倒くさがりな)僕はよくこうしてます。
vimのIMEが勝手にオンになるのはset iminsert=0 imsearch=0とかでどうでしょうか?
minkeさん:<br>おお、そういう風になっていたのか…。僕も頑張って読んでみます。<br>k.inabaさん:<br>ありがとうございます。試してみたのですが、今度はリストのリスト(具体的には[[Int]])の中の数値リテラルの型が曖昧だと怒られるようになりました。<br>もうちょっと試行錯誤してみます。<br>---<br>foo.hs:24:28:<br> Ambiguous type variable `t' in the constraints:<br> `Num t' arising from the literal `1' at foo.hs:24:28<br> `SexpValue t' arising from a use of `toSexp' at foo.hs:24:19-39<br> Probable fix: add a type signature that fixes these type variable(s)
class SexpValue a where<br> toSexp :: (SexpValue a) => a -> String<br> toSexpList :: (SexpValue a) => [a] -> String<br> toSexpList ls = "(" ++ (concat $ intersperse "," (map toSexp ls)) ++ ")"<br><br>instance SexpValue Int where<br> toSexp n = show n<br>instance SexpValue Char where<br> toSexp c = show c<br> toSexpList s = s<br>instance SexpValue a => SexpValue [a] where<br> toSexp l = toSexpList l<br><br>こんな感じにしてやると、<br>*Main> toSexp [["abc","def"],["ghi","jk"]]<br>"((abc,def),(ghi,jk))"<br>*Main> toSexp [[[1,2],[3,4]],[[5],[6],[7::Int]]]<br>"(((1,2),(3,4)),((5),(6),(7)))"<br>みたいになります。
バックスラッシュの入力は、Alt + バックスラッシュでいけたりしませんかね?<br>いや、試していないのですが・・・
b2oxさん:<br>ありがとうございます。なるほど、7::Intのように型を明示的に指定してやればいいんですね。<br>Yuyaさん:<br>おおおできた!Altは押しにくいですけど日本語IMを経由するよりはだいぶ楽でいいですね:-)