SHPLIT

SHPLIT is the Strathclyde Haskell Pattern LIsting Tool. It makes use of type information to figure out how to split a pattern variable into its possible constructor forms. It's at a rather experimental stage, just now, so caveat emptor. This directory is also a darcs repo.

The main shplit executable is a transducer, taking a .hs file (sorry, no .lhs yet) from stdin and splatting a modified version of the same to stdout. The associated lump of emacs lisp, if suitably pasted into your .emacs, or whatever, should enable you to process the buffer with M-x shplit-buffer, or attack the variable at point with M-x shplit-this (bound to C-c C-c).

SHPLIT knows about a few standard datatypes, and the datatypes declared in the input. A future version might be kind enough to chase modules. SHPLIT can't handle records or GADTs. SHPLIT works only on top-level prefix functions with an explicit (Hindley-Milner) type signature. It's for beginners, just now.

To indicate that you want to shplit a pattern variable, just bung {-?-} in the source code after it. Like this

  foo :: [x] -> [x]
  foo xs{-?-} =
Note that the = is needed as a clue that it's a program line, but a right-hand side is not compulsory (and will be crudely copied). You should get
  foo :: [x] -> [x]
  foo [] =
  foo (x : xs) =
back. SHPLIT tries to be slightly cunning with names, and is happy to do more than one shplit at a time.
  goo :: [x] -> [x] -> [x]
  goo xs{-?-} ys{-?-} =
yields
  goo :: [x] -> [x] -> [x]
  goo [] [] =
  goo [] (y : ys) =
  goo (x : xs) [] =
  goo (x : xs) (y : ys) =

There's plenty of room for improvement. It only took me a day to knock it together. But it's fun to play with.

Setting up your datatype

If you just write any old Haskell 98 datatype, SHPLIT will make up a vaguely sensible naming scheme, but you can roll your own, by annotating your datatype declaration. Here's what I used for lists.

  data {-xs-}[] x = [] | {-x-}x : {-xs-}[x]
The annotation on the type head is a crude string pattern. All but the first character match one character of the variable being split, and the first character matches any remaining prefix. So matching xs against a pattern variable yss would bind x to ys and s to itself. If the pattern variable is too short, the overhanging characters match themselves, so matching xs against l would bind s to l and x to itself. The resulting substitutions are then applied to the name annotations which accompany each constructor argument. So if the pattern variable is yss, it splits as [] or (ys : yss).


Last modified: Thu Jan 19 16:13:04 GMT 2012