EAGLE 雑記 このページをアンテナに追加 RSSフィード

Tue November 29, 2011

[][] GHC API を使ってある型コンストラクタのデータコンストラクタを得る

neco-ghc などで,Haskell 用の補完候補をより正確に計算するときに活用できないかなーと思った.

GHC 7.0.3 で試した.


あるモジュールエクスポートしている名前は modInfoExports でとれる.

そのモジュールで定義されていれば modInfoTyThings で TyThing をとれるけど,例えば aeson の Data.Aeson のように他のモジュールからインポートしたものをエクスポートしている場合,名前は modInfoExports には含まれているけど TyThing が modInfoTyThings に含まれていない,ということが発生する.

なので,modInfoExports で得た名前に関して lookupName で改めて問い合わせて TyThing を得ている.


コンパイルするときは

% ghc -package ghc Browse.hs

と明示的に -package ghc をつけてやる必要がある.

import GHC
import GHC.Paths (libdir)
import MonadUtils (liftIO)
import Name
import Data.Maybe (catMaybes)
import Control.Applicative ((<$>))
import System.Environment (getArgs)

main :: IO ()
main = do
  args <- getArgs
  runGhc (Just libdir) $ do
    getSessionDynFlags >>= setSessionDynFlags
    mapM_ browse args

browse :: GhcMonad m => String -> m ()
browse m = do
  xs <- maybe [] modInfoExports <$> lookupModuleInfo >>= collapseData
  liftIO $ mapM_ putStrLn xs
  where
    lookupModuleInfo = findModule (mkModuleName m) Nothing >>= getModuleInfo
    collapseData = fmap (map expand . catMaybes) . mapM lookupName . filter (not . isDataConName)
      where
        expand (ATyCon ty) = unwords $ (getOccString ty :) $ map getOccString $ tyConDataCons ty
        expand t = getOccString t

ghc-mod browse との違い

% ghc-mod browse -o Data.Aeson
(.:)
(.:?)
(.=)
Array
Array
Bool
DotNetTime
DotNetTime
Error
FromJSON
Null
Number
Object
Object
Result
String
Success
ToJSON
Value
encode
fromDotNetTime
fromJSON
json
object
parseJSON
toJSON
% ./Browse Data.Aeson
encode
json
.:
.:?
.=
Array
DotNetTime DotNetTime
fromDotNetTime
FromJSON
parseJSON
Object
Result Error Success
ToJSON
toJSON
Value Object Array String Number Bool Null
fromJSON
object

Sun November 14, 2010

[][] GHCi.vim

inf-haskell.el から最低限の機能を抜き取ったかんじの Vim script 書いた.

https://github.com/eagletmt/ghci-vim

使い方としては <LocalLeader>l でファイルをロードした後に,<LocalLeader>t で型を見たり <LocalLeader>i で info を見たり.

vimproc のおかげで Vim からプロセスと会話できる.ありがたい.

最初は vimshell の VimShellInteractive でいいかなーと思ってたんだけど,欲しかったのは GHCi を使うことというより GHCi を利用して情報を表示することだったので,このような実装にした.


あとエディタでやりたいのはドキュメントの閲覧だけどこれのうまいやり方が思い付かない.

haskell-mode を見たところ,ghc-pkg とかでパッケージとモジュールの対応をつけて {package}-{ver}/html/{module}.html#v:{symbol} をブラウザで開いているようだった.

うーん…

Sun August 08, 2010

[][] GHC APIモジュールが export している名前とその型を得る

./BrowseType Prelude のように使うと

(snip)
break = forall a. (a -> GHC.Bool.Bool) -> [a] -> ([a], [a])
catch = forall a. GHC.Types.IO a -> (GHC.IO.Exception.IOError -> GHC.Types.IO a) -> GHC.Types.IO a
ceiling = forall a. (GHC.Real.RealFrac a) => forall b. (GHC.Real.Integral b) => a -> b
compare = forall a. (GHC.Classes.Ord a) => a -> a -> GHC.Ordering.Ordering
concat = forall a. [[a]] -> [a]
concatMap = forall a b. (a -> [b]) -> [a] -> [b]
const = forall a b. a -> b -> a
cos = forall a. (GHC.Float.Floating a) => a -> a
cosh = forall a. (GHC.Float.Floating a) => a -> a
curry = forall a b c. ((a, b) -> c) -> a -> b -> c
cycle = forall a. [a] -> [a]
decodeFloat = forall a. (GHC.Float.RealFloat a) => a -> (GHC.Integer.Type.Integer, GHC.Types.Int)
(snip)

のように表示される.


以下 GHC API に関してメモ.

名前とその型は TyThing によって関連付けられている.

AnId が変数名 (型は Id になっているが,これは Var のエイリアス),ADataCon が data constructor,ATyCon が type constructor,AClass がクラス.

Var も DataCon も NamedThing なので getOccString で String にできる.

Var と DataCon はそれぞれ varType, dataConType で Type に変換することができ,Type は Outputable なので ppr で SDoc にできる.

なぜか showSDocOneLine の定義で PageMode が指定されていて全然 OneLine じゃないので,上のコード中では自分で OneLineMode を指定して String にしている.


TyThing を得るために最初は modInfoTyThings を使っていたが,これだとそのモジュールが export しているもの全てはとってこれないので,まず modInfoExports で export されている名前を得てからそれぞれに対して lookupName で TyThing を得る必要がある (たぶん).

Sun May 09, 2010

[][] ここの型を知りたい

こんなかんじに使う.

% echo 'length x' | ./hint
[a]
% echo 'x + 1' | ./hint
(GHC.Num.Num a) => a
% echo 'foldl x 0 [2,3]' | ./hint
(GHC.Num.Num a, GHC.Num.Num b) => a -> b -> a
% echo 'nub x' | ./hint Data.List
(GHC.Classes.Eq a) => [a]

元ネタは

GHC APIにLHsExpr,TyThingがあるので、f ? a bっていう式の?の型が知りたい!!ってときに\x -> f x a bと変形し型を推論させたTyThingからxに相当する部分を取り出すことでagda2-modeの?みたいなものを作れそうですね

http://twitter.com/hogehogefoobar/status/13598939209

これなんだけど,f ? a b を \x -> f x a b に変形する方法がわからなかったので,\x -> f x a b の状態で x の型を表示するようにしてみた.


コンパイルには ghc-paths が必要.

http://gist.github.com/394878