[Haskell-cafe] Re: [Haskell] ANN: HLint 1.0

Gwern Branwen gwern0 at gmail.com
Sat Dec 20 13:10:44 EST 2008


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

So has anyone figured out how to integrate hlint with ghci? I've tried
several approaches.

Using hlint as a preprocessor (
http://www.haskell.org/ghc/docs/latest/html/users_guide/options-phases.html#pre-processor
) doesn't work because the pre-processor needs to take 3 args. Even if
one writes a wrapper shell script along the lines of 'cp $2 $3 &&
hlint $2', this still won't work. It apparently breaks when you load a
file which requires another file. I am not sure why.

I then thought to redefine :load and :reload in ghci; this would work
very well with Emacs and Yi, since they tell ghci to :load and :reload
buffers. Turns out, you're not allowed to overwrite :load and :reload.
You can do :def reload whatever to your heart's content, but the new
version never takes. (Not even if defined in .ghci.)

Alright. A :hlint would probably be enough. I can always edit Yi/Emacs
to follow a :reload/:load with a :hlint, after all. And aren't there
shell command primitives already?

So I set out, and I realize: I can't simply settle for some version of
:! "hlint .", because the working directory rarely changes - if one
opens ghci in ~/, and loads a file elsewhere, :pwd reveals one to
still be in ~/. And a 'hlint .' could take a very long time indeed in
~/.

Well, alright. I just need the file name of the module I'm working
with. Surely there is an easy way to do that. And indeed, :show
modules gives me what I'm looking for:

*Recorder Control.Monad Data.Char Data.List> :show modules
Util             ( Util.hs, interpreted )
Recorder         ( Recorder.hs, interpreted )
Game             ( Game.hs, interpreted )
Monadius         ( Monadius.hs, interpreted )
Demo             ( Demo.hs, interpreted )

Well, sort of. Ok, we can parse that. Let's assume a variable x holds
the output of :show modules as a String. We call lines on it, then map
words on it, do a !! 2 on it, and we get ["Util.hs,", "Recorder.hs,",
"Game.hs,", "Monadius.hs,", "Demo.hs,"]. Chuck in a map (filter (\=
',')), and we get a good list. We can turn the list into a string
suitable for hlint with a quick unwords.

So our long sought after command becomes ':def hoogle (\_ -> return $
":! " ++ (unwords $ map (filter (\= ',')) $ (map words $ lines x) !!
2))'. But wait, how do we get 'x'? How do we call :show modules inside
a Haskell expression? I have carefully looked over
http://haskell.org/haskellwiki/GHC/GHCi#Using_GHCi and
http://www.haskell.org/ghc/docs/latest/html/users_guide/ghci-commands.html
and my conclusion is that you can't. You can't do a let x = :show
modules, there is no function which will take ":show modules", and so
on. :functions can accept Haskell output, but it's a one-way barrier.
It's no good writing Haskell functions which need information from the
:functions.

Which all leaves me where I started - no ghci integration with hlint. Any ideas?

- --
gwern
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (GNU/Linux)

iEYEAREKAAYFAklNNSIACgkQvpDo5Pfl1oJwWgCfZJ7nwkHfsZymIRass0ewmhFE
en4AnjmQam3V8Go6pGoLTRsp5zZEzAms
=nmJm
-----END PGP SIGNATURE-----


More information about the Haskell-Cafe mailing list