2011年7月31日日曜日

構文チェックツールのFlymakeを、Haskell用に設定する方法


Emacsでは、Flymakeを使うことで、コードを書くと随時文法チェックが行われ、エラーのある行がバッファ上に表示されるようになる。

Haskell用にFlymakeを設定したので、その設定を書いておく。.emacsを編集するだけでOKだ。

Flymakeでは、基本的にコードと同じディレクトリにあるMakefileを使って文法チェックを行う形になっているが、いちいちMakefileを用意するのは煩わしいので、Makefileなしでも動作するようにした。特定のパラメータが必要な場合などは、Makefileを用意すれば自動的にそちらを使って文法チェックが行われるようにしてある。

.emacsの設定


以下のelispを.emacsに追加するだけでOK。

※Emacs21以前の場合は、flymake.elが標準で付属していないので、自分でインストールする必要がある。Emacs22以降であれば、標準で付属している。
;; Flymake Haskell

(require 'flymake)

(defun flymake-haskell-make-command (temp-file)
  (list "make"
        (flymake-haskell-make-parameters temp-file)))

(defun flymake-haskell-make-parameters (temp-file)
  (list "-s"
        "-C"
        "."
        (concat "CHK_SOURCES=" temp-file)
        "SYNTAX_CHECK_MODE=1"
        "check-syntax"))

(defun flymake-haskell-default-ghc-command (local-file)
  (list "ghc"
        (flymake-haskell-default-ghc-parameters
          (file-name-nondirectory local-file))))

(defun flymake-haskell-default-ghc-parameters (local-file)
  (list "-fno-code" local-file))

(defun makefile-exists-p (path)
  (file-exists-p (concat path "Makefile")))

(defun flymake-haskell-init()
  (let* ((temp-file  (flymake-init-create-temp-buffer-copy
                       'flymake-create-temp-inplace))
         (local-file (file-relative-name
                       temp-file
                       (file-name-directory buffer-file-name))))
    (if (makefile-exists-p (file-name-directory buffer-file-name))
        (flymake-haskell-make-command temp-file)
        (flymake-haskell-default-ghc-command local-file))))

(push '(".+\\hs$" flymake-haskell-init) flymake-allowed-file-name-masks)
(push '(".+\\lhs$" flymake-haskell-init) flymake-allowed-file-name-masks)
(push '("^\\(\.+\.hs\\|\.lhs\\):\\([0-9]+\\):\\([0-9]+\\):\\(\.+\\)" 1 2 3 4)
      flymake-err-line-patterns)

(add-hook 'haskell-mode-hook
    '(lambda ()
       (if (not (null buffer-file-name))
           (flymake-mode))))

説明


flymakeの有効化
add-hookによって、haskell-modeに入ったときに(flymake-mode)が実行される。

拡張子の対応付け、エラーメッセージの正規表現の定義
add-hookの上でpushしているのは、Haskellの.hsファイル、.lhsファイルとflymakeの初期化関数との紐付け、及び、ghcの出力から行番号やエラーメッセージを抽出するための正規表現である。

flymake haskellの初期化
flymake-modeに入ると、flymake-haskell-initが実行される。flymake-haskell-initでは、構文チェック用にコードをコピーし、そのコードを構文チェックするためのコマンドをflymake本体に返している。このとき、チェック対象のコードと同じディレクトリにMakefileがあるかどうかでコマンドを変えている。

チェック対象のコードと同じディレクトリにMakefileがある場合
この場合、構文チェックのコマンドはflymake-haskell-make-command関数によって生成される。flymakeがデフォルトで使用するmakeコマンドと同じものを生成している。

チェック対象のコードと同じディレクトリにMakefileがない場合
一方、この場合は、Makefileなしで構文チェックを行うよう、GHCを使ったコマンドを、flymake-haskell-default-ghc-command関数で生成している。生成するコマンドの形式は、
("ghc" ("-fno-code" 構文チェック用ファイルの名前))
となる。外側のリストのcarがghcコマンド、cadrがghcコマンドに渡すパラメータのリストである。これがflymakeに渡され、実行される。

補足


flymakeではエラーメッセージも表示してくれるのだが、ghcが複数行にわたるエラーメッセージを返す場合にはうまく処理できない。

flymakeは、それだけで完全にコンパイルをとおすためではなく、コードを書くときのタイポ回避程度に位置づけると良いだろう。

参考


http://www.emacswiki.org/emacs/FlymakeHaskell




--

2011年7月23日土曜日

【まとめ】埋め込みDSL関係の論文(2)


引き続き、埋め込みDSL(Domain Specific Language)関係の論文をまとめたので書いておく。

Template Meta-programming for Haskell (2002) - Tim Sheard, and Simon Peyton Jones
→Haskellでコンパイル時メタプログラミングを行うTemplate Haskellの論文

A Special-Purpose Language for Picture Drawing (1997) - Samuel N. Kamin, and David Hyatt
→MLを使って、2次元の絵を表現するための組み込みDSLを作る

Compiling Embedded Languages (2000) - Conal Elliott, Sigbjorn Finne, and Oege de Moor
→Kaminのプログラム生成のアイデアを元に、組み込みDSLの最適化コンパイラを示す。計算効率が重要な分野の応用例として、この方法を画像合成・操作のための言語Panに適用する。

Functional Implementations of Continuous Modeled Animation (1997) - Conal Elliott, and Paul Hudak
→連続的アニメーションのモデルを設計し、それを試作として実装してみせる。

Programming Graphics Processors Functionally (2004) - Conal Elliott
→3Dグラフィクスのための組み込みDSLであるVertigoを紹介する。VertigoはHaskellで書かれている。Vertigoは、GPUのコードを生成する最適化コンパイラである。

Functional Reactive Animation (1997) - Conal Elliott, and Paul Hudak
→インタラクティブでリッチなアニメーションを構築するためのフレームワークFRAN(Functional Reactive Animation)を紹介する。

Building Domain-Specific Embedded Languages (1996) - Paul Hudak
→良いソフトウェアを書くには抽象化が重要であり、最も"理想的"な抽象化は問題に合わせて設計されたプログラム言語を作ることであるとして、その障害である言語設計と実装の困難さを、組み込みDSLというアプローチで回避することを提案する。

Applicative programming with effects (2008) - Conor McBride, and Ross Paterson
→副作用を持つプログラムの抽象化の方法として、Monadよりも弱いため広く使えるApplicativeファンクタを紹介する。

Arrows, Robots, and Functional Reactive Programming - Paul Hudak, Antony Courteny, Henrik Nilsson, and John Peterson
→FRP(Functional Reactive Programming)の実例として、Haskellによる組み込みDSLであるYampaを紹介する。Yampaではモナドの一般化としてアローを使用する。Yampaによって、時間変化を扱うプログラムを宣言的なスタイルで実現できる。


■関連エントリ

【まとめ】埋め込みDSL関係の論文(1)

--

2011年7月8日金曜日

【まとめ】埋め込みDSL関係の論文(1)


埋め込みDSL(Domain Specific Language)関係の論文をまとめたので書いておく。

Plugging Haskell in (2004) - Andre Pang, Don Stewart, Sean Seefried, and Manuel M. T. Chakravarty
→Haskellをプラグインとして使う方法を紹介している。紹介されているプラグインは、HaskellでもHaskell FFIがサポートしている他の言語でも使用できる。GHCで提供されている仕組みを使って、プラグイン、実行時コンパイル、動的リンクを実現する方法を示している。また、サンプルも紹介されている。

Standard ML as a Meta-Programming Language (1996) - Samuel Kamin
→Standard MLをメタプログラミング言語として使うことを提案し、4つの実例を示している。Standard MLのコードからCのコードを生成。

Building program generators the easy way - Samuel Kamin
→関数型プログラミング言語で簡単にプログラムジェネレータを作ることができることを紹介している。この方法によって、ソフトウェア開発に関数型プログラム言語を便利に応用できる可能性を示している。

Effecient Image Manipulation via Run-time Compilation (1999) - Oege de Moor, Conal Elliott, and Sigbjorn Finne
→DSLとして定義したイメージ操作システムを、実行時に最適化・コンパイルすることで、その効率化する方法を紹介している。

Optimizing Embedded DSLs using Template Haskell (2004) - Sean Seefried, Manuel Chakravarty, and Gabriele Keller
→コンパイル時メタプログラミングによってEDSLの実行効率を改善する方法を示している。EDSLとしてのシンプルさを保ったまま実行効率を改善する。

GPU Kernels as Data-Parallel Array Computation in Haskell (2009) - Sean Lee, Manuel M. T. Chakravarty, and Vinod Grover
→HaskellにGPUカーネルを埋め込んでデータ並列の配列計算を行う方法を示している。

Accelerating Haskell Array Codes with Multicore GPUs (2011) - Manuel M. T. Chakravarty, Gabriele Keller, Sean Lee, Trevor L. McDonell, and Vinod Grover
→GPUコーンピューティングの抽象度を上げるために、配列計算の高レベルDSLを提案する。HaskellにこのDSLを埋め込み、NVIDIAのCUDAのためのコードを実行時に生成する。


■関連エントリ

【まとめ】埋め込みDSL関係の論文(2)

--

2011年7月6日水曜日

Language-oriented programming


A kind of programming that's quite common in Common Lisp and relatively uncommon in non-Lisp Languages.

Rather than provide an API built primarily out of functions, classes and macros, language-oriented programming provides language that you can embed in your Common Lisp programs.



--

2011年7月5日火曜日

LispマクロとTemplate Haskellの違い


LispマクロとTemplate Haskellには違いがある。

LispのマクロはS式を変換する。一方、Template Haskellが変換するものはHaskellのAST(Abstract Syntax Tree)である。

従って、Template Haskellで変換できる式は、まずASTとして有効でなければならない。ASTとして有効な式でなければTemplate Haskellに渡せない。Lispの場合はS式でさえあれば良い。シンボルをただ並べたリストでも良い。

制限が小さい分、Lispマクロの方が強力だといえるだろう。



--

2011年7月4日月曜日

【書評】実用Common Lisp

実用Common Lisp では、人工知能(AI)、コンピュータプログラミング技術、Common Lispを扱っている。原題はParadigms of Artificial Intelligence Programming : Case Studies in Common Lisp。

「第7章 STUDENT:代数の文章題を解く」
代数の文章題を解く。方法は、文章題を代数の数式に変換してそれを解くというもの。自然言語(英語)と数式の翻訳表をプログラムとして持つ。

「第8章 記号計算:簡単化プログラム」
Common Lispの数式処理システムであるMaximaのサブセットを作る。

「第9章 効率性の問題」
高速化の手法の1つとしてコンパイルをとりあげる。宣言的に記述された問題を、マクロを使ってコンパイル時にLispコードに変換する。

こういうのを「知能」だと見なしていた時代があったんだなぁ。

Lispは人工知能の分野で使われるというが、その理由が腹落ちした。この本によると、解き方が不明な問題に対するアプローチとしては、問題をそのまま宣言的に記述しそれをプログラムコードに変換するプログラムを書くのが適切であるという。そのような問題を扱う代表例がAIだった。そして、宣言的に記述された問題をプログラムコードに変換するのにLisp(のマクロ)が向いていたということだった。