org-babel で runhaskell を使いたい
Haskell で org-babel してみた
周りのみんなと Haskell の勉強をしています. めいめいが作った練習問題の解答集を org-mode で書きたくて, Haskell でも org-babel 使ってみました. 何だか yak shaving はじまりの予感です.
例えば,こんなプログラム:
let sumPositive = sum . filter (>0) sumPositive [1, 2, -1, 5]
org-mode では,こんな感じに書きます:
#+BEGIN_SRC haskell let sumPositive = sum . filter (>0) sumPositive [1, 2, -1, 5] #+END_SRC
コード上で C-cC-c で eval されて以下が自動挿入されます. 裏で GHCi が動いているようです.
: 8
ただ, let
を毎回入力したくない.
あと, IO
を書こうとすると,GHCi じゃなく,
runhaskell を使いたくなります(?).
ですが,ob-haskell.el は,そこまで考慮していないようです
(以前MLで議論はあったようですが).
Quickhack
本来なら ob-C.el とかを見ながら頑張るのが筋ですが, 締切前にそんな悠長な事はできないので,
- GHCi のフリをしつつ,runhaskell を動かす wrapper
runhaskell-ob
を用意する. - org-babel の block パラメータに :results output があった場合は,
GHCi ではなく,
runhaskell-ob
を使うように defadvice する.
で切り抜けることにしました.
runhaskell-ob:
#!/usr/bin/env ruby delimiter = '"org-babel-haskell-eoe"' prompt = "hello> " def execute_haskell(body) io = IO.popen("runhaskell", "r+") io.write(body) io.close_write result = io.read io.close return result end print prompt body = '' while line = gets if line =~ /#{delimiter}/ result = execute_haskell(body) result.split(/\n/).each do |str| print "#{str}\n" print "#{prompt} \n" end print "#{prompt} \n" print "#{delimiter}\n" print prompt body = '' else body += line end end
.emacs に追加:
;; use runhaskell when :results is output (defadvice org-babel-haskell-initiate-session (around org-babel-haskell-initiate-session-advice) (let* ((buff (get-buffer "*haskell*")) (proc (if buff (get-buffer-process buff))) (type (cdr (assoc :result-type params))) (haskell-program-name (if (equal type 'output) "runhaskell-ob" "ghci"))) (if proc (kill-process proc)) (sit-for 0) (if buff (kill-buffer buff)) ad-do-it)) (ad-activate 'org-babel-haskell-initiate-session)
これで,以下のように :results output を付けて書くと,
#+BEGIN_SRC haskell :results output sumPositive = sum . filter (>0) main = do print $ sumPositive [1, 2, -1, 5] #+END_SRC
let がなくても,main があっても一応動作します.
sumPositive = sum . filter (>0) main = do print $ sumPositive [1, 2, -1, 5]
結果:
8
どうやら,締切に間に合いそうです.