2014年2月23日日曜日

[Haskell][Emacs]Hoogleをローカルで使う

Hoogleをローカルで使ってみた。
ついでに、Hoogle検索できる、少しだけ便利なELispを書いた。

インストール

cabalでインストールできる。
$ cabal install hoogle
多くのライブラリに依存しており、インストールには少し時間がかかる。
データベースを作成する。
$ hoogle data
データベースのダウンロードに少し時間がかかる。

試してみる

$ hoogle Data.List
Data.List module Data.List
package List
package ListLike
package ListTree
package ListZipper
Data.Maybe listToMaybe :: [a] -> Maybe a
package list-extras
package list-grouping
〜以下略〜

検索できたが、テキストベースだとちょっと見難い。

サーバーにする

サーバーとしても起動できる。
以下の例は3000番ポートで起動する場合。
$ hoogle server --port 3000

ブラウザから http://localhost:3000/ を開くと、
見慣れたHoogleの画面が表示される。

EmacsでHoogle検索

EmacsからHoogleを直接検索できると便利だけど、誰か作っていないかな?
とりあえず、browse-url で検索文字列をHoogleに渡して、w3mで表示できると便利そうなので、作ってみた。

;;; w3mをデフォルトにする場合は以下をコメントアウトする
;;(require 'w3m-load)
;;(setq browse-url-browser-function 'w3m-browse-url)

(defun hoogle (keyword)
  (interactive "sKeyword:")
  (let ((url (format "http://localhost:3000/?hoogle=%s" keyword)))
    (browse-url url)))

M-x hoogle 検索文字列を入力すると、Emacs上に検索結果を表示する。
なかなか便利だけど、検索結果画面内のリンクの先は hackage.haskell.org なのか。
ここから先もローカルにできると良いのだけど。

参考


2014年2月11日火曜日

[Haskell] handle関数の例外処理部分で The type variable `e0' is ambiguous

Real World Haskell 9章 にならって、
ファイルサイズを取得するコードを書いたところ、

getFileSize :: FilePath -> IO (Maybe Integer)
getFileSize path = handle (const (return Nothing)) $ do
                     h <- openFile path ReadMode
                     size <- hFileSize h
                     hClose h
                     return (Just size)


以下のようなエラーが発生した。
例外の型が複数定義されていて、あいまいなので、型を明示しろというエラーのようだ。

    No instance for (GHC.Exception.Exception e0)
      arising from a use of `handle'
    The type variable `e0' is ambiguous
    Possible fix: add a type signature that fixes these type variable(s)
    Note: there are several potential instances:
      instance GHC.Exception.Exception GHC.IO.Exception.ArrayException
        -- Defined in `GHC.IO.Exception'
      instance GHC.Exception.Exception GHC.IO.Exception.AssertionFailed
        -- Defined in `GHC.IO.Exception'
      instance GHC.Exception.Exception GHC.IO.Exception.AsyncException
        -- Defined in `GHC.IO.Exception'
      ...plus 15 others
    In the expression: handle (const (return Nothing))
    In the expression:
      handle (const (return Nothing))
      $ do { h <- openFile path ReadMode;
             size <- hFileSize h;
             hClose h;
             return (Just size) }
〜以下略〜

例外の型に応じた処理をしないのならば、どのような例外の型にもあうSomeExceptionがControl.Exceptionモジュールに定義されているので、それを使えば良い。

getFileSize path = handle (\(SomeException _) -> return Nothing) $ do 〜

最終的には、例外発生時でもファイルハンドルを必ず閉じるように、bracketを使って、以下のコードとなる。
getFileSize :: FilePath -> IO (Maybe Integer)
getFileSize path = handle (\(SomeException _) -> return Nothing) $ do
                     bracket (openFile path ReadMode) hClose $ \h -> do
                       size <- hFileSize h
                       return (Just size)


参考

          

[Haskell] getModificationTime は ClockTime を返さない

Real World Haskell 9章では、ファイルの更新日を取得に
getModificationTime を使うコードが提示されている。
ghc 7.6.3 で試したところ、エラーとなった。
書中では、この関数は ClockTime型を返すようになっているが、現在は ClockTime型は obsolute になっており、System.Directory.getModificationTime は UTCTime を返すようになっていた。

いろいろ調べてみると、System.EasyFile というモジュールがあった。
説明によると、
> This is a module of cross-platform file handling for Unix/Mac/Windows.
であり、
ファイルの更新日、作成日、アクセス日の取得、シンボリックリンクの判定、パスセパレータの統一化等、便利な関数が提供されている。

$ cabal install easy-file
でインストールできる。

2014年2月8日土曜日

[Haskell][Emacs]inferior-haskellで起動するghciにオプションを設定する

Emacsのhaskell-modeで、haskellのコードを書いている。
inferior-haskell-load-file(C-c C-l)で、ghciでコードをすぐに評価できるので便利である。
しかし、プラグマ指定で、
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
と書いて、
inferior-haskell-load-fileしても、Emacsから起動したghciでは、上記のオプションが有効になっておらず、エラーとなってしまった。
これに対処するには、inferior-haskellが起動するコマンドは、引数と一緒にhaskell-program-nameで設定できるので、以下のようにEmacsの初期化ファイルに書けばよい。
(setq haskell-program-name "ghci -XTypeSynonymInstances -XFlexibleInstances")