[Haskell-cafe] advice: instantiating/duplicating modules

Dave Bayer bayer at cpw.math.columbia.edu
Fri Jun 29 21:29:20 EDT 2007

On Jun 29, 2007, at 10:07 AM, Nicolas Frisby wrote:

> I wrote a combination reader/writer monad (a la the RWS monad in the
> mtl) and I find myself wanting to use multiple instances of it in the
> same stack of transformers. The functional dependencies prevent this
> from working out.

I found myself in a situation implementing two very similar  
algorithms where I had to really puzzle out how to get functional  
dependencies to work, and I ended up writing a class (I abridge):

> class (Num b, Real c) => Elem a b c | a -> b, a -> c where
>    qr :: a -> b -> b -> QR c

and then declaring instances like

> data Rlist a = Rlist
> instance Integral a => Elem (Rlist a) a (Ratio a) where
>    qr w x y = Yes (x % y) False

When I wanted this version of qr, I'd call "qr Rlist". Rlist is a  
dummy class parameter to get the functional dependencies to work, it  
does nothing besides select a version of my code. I couldn't get the  
functional dependencies to work out any other way, so I accepted this.

Later, I realized that Haskell had named records, and I went back and  
rewrote stuff as follows:

> data (Num b, Real c) => Elem b c = Elem {
>     qr :: b -> b -> Rem c }
> rlist :: Integral a => Elem a (Ratio a)
> rlist = Elem {
>     qr = (\x y -> Just (x % y, False)) }

Now all I had to do was change the case from "qr Rlist" to "qr rlist"  
and the rest of my code worked exactly as before. (I love how often  
this sort of thing happens in Haskell.) I went from thinking that  
passing around a bunch of functions was kludgey, to thinking that a  
beginner like me using multi-parameter type classes unnecessarily was  
obfuscation. In any case, it didn't matter what I thought, the code  
either way was virtually identical.

I've since done some experiments with Template Haskell, and I see  
that Arie Peterson has suggested how you could proceed. However, are  
you sure that you can't find a way to get this to work in vanilla  
Haskell without extensions? Or, for that matter, are you sure there  
isn't a way to get functional dependencies to work? (I felt pretty  
dumb for a little while before I found one for my problem, although  
as usual the issues are clear in hindsight.)

More information about the Haskell-Cafe mailing list