I have been trying to get some real work done with [Haskell](http://www.haskell.org) – shock, horror! As part of that I am using the excellent [HaskellDB](http://haskelldb.sourceforge.net/) combinator library for type-safe and composable database operations. HaskellDB employs some advanced type constructs such as [phantom types](http://www.haskell.org/hawiki/PhantomTypes), which can result in rather complex types that make analyis of type errors a bit of a challenge. It also makes it tricky to produce type annotations for the code by hand, e.g. for documentation purposes. One can of course ask haskell for the type, and then just stick that in the annotation, but the types one gets this way do not make for pleasent reading and require exposure of a whole bunch of HaskellDB’s typing guts.
By far the most weird typing issue I ran into though is when I had two identical (in all but name) functions, one of which was being used in my code and the
other one wasn’t:
intervalIds = map $ flip (!) TaskTime.xid — used
intervalIds’ = map $ flip (!) TaskTime.xid — not used
The type checker chokes on the latter with
No instance for (Select (Attr Task_time.Id Int) a a1)
arising from use of `!’ at Model.hs:59:26-28
add an instance declaration for (Select (Attr Task_time.Id Int)
In the first argument of `flip’, namely `(!)’
In the second argument of `($)’, namely `flip (!) Task_time.xid’
In the definition of `intervalIds”:
intervalIds’ = map $ (flip (!) Task_time.xid)
So it looks like the use of `intervalIds` places sufficient constraints on the typing to make the function typable, and the absence of such constraints for `intervalIds’` results in an untypable expression.
On reflection this is not really surprising. A number of the advanced typing features of haskell are not amenable to type inference and hence require explicit type annotations. However, as explained above, coming up with these annotations is not always easy or desirable.