■
(>>=)演算子の引数の順がKleisli Tripleと合ってなくて、キモイと思ったけど、(>>=)は結合律を満たすので、中置記法にするのは自然。(bind f (bind g h))だと、結合律が陽に見えない。そして、敢えて、引数の順序を入れ替えることで、中置記法にした時、例えば「一文字受け取って、それをputする」という処理が
main = getChar>>=(\it -> putChar it)
のように、自然言語の記述を頭からそのまま直訳できると。where節なんかもそうだけど、Haskellは、実は、自然言語の記述を(なるべく先読み、後戻りせずに)頭から読み書きするのに便利なように設計されてるのかも。そういう点では、最も初心者向きな言語かもしれない。エラーが出たら意味不明だろうけど
それSchemeでもできるよ!
(define (main) (cond ((read) => (lambda (it) (eval it (interaction-environment))))))
真面目に言うと、継続引渡しスタイルで書くのがScheme流なんだろうけど、あれだと結合律が見えないとか、まあなんかそんな
さて、こないだの多項式のパーサー部分(runとpparse)が、行き先がMaybeモナド限定だったり、fromJustで無理やり値取り出してたり、色々ダメだと分かった。よりHaskellっぽいのは、こう(多分)
run :: (Monad m , Show t) => Parser t -> String -> m t run p input = case (parse p "" input) of Left err -> fail "parse error" Right x -> return x pparse str = (run polynomial_expr str)
できるだけ、データ構造の詳細に依存しないように関数を作る。ところが、こうすると、pparse::(Monad m)=>String->m (Polynomial Integer)とかなるので、normalizeを素直に適用できなくなる。normalizeは引数が多項式に限定されてれば必ず成功することが保証されているけど、pparseは、入力によっては、失敗する可能性があるので、このへんの摺り合わせが面倒だなー。まあ、普通は、do使うんでしょう
do{p<-(pparse "3*4+t*x*6+12*(u+t)");putStrLn (show (normalize p))}
んー、けど、normalize (pparse ...)って書きたいなー。liftMを使えば、直接適用できるけど、liftMすべきかどうか考えるのは非直感的な気も。折角なので、(>>=)と(>>)だけで繋げて書く練習。このへん色々書き方があるけど(私が試したので、十通り以上)、最短なの
(pparse "3*4+t*x*6+12*(u+t)")>>=(putStrLn . show . normalize)
関数合成は適用順序と書く順序が逆になるので、いやだ。「パース→正規化→文字列化→出力」という思考の流れを忠実に表現
(pparse "3*4+t*x*6+12*(u+t)")>>=(return . normalize)>>=(return . show)>>=putStrLn
(return . xxx)とかうざい
pipe a b = a>>=(return . b) (pparse "3*4+t*x*6+12*(u+t)") `pipe` normalize `pipe` show>>=putStrLn
というわけで、pipeみたいな演算の簡潔な記法があればいいと思った。liftMと一緒で、どこで(>>=)で繋げて、どこでpipeで繋げるか迷いそうだけど。よくreturn忘れるというのもそうだけど、このへんはHaskellに慣れればどうにかなるのか。