advice: instantiating/duplicating modules

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. The class is called MonadRW and the transformer is called RWT. I find myself wishing I could import the same module twice, but instead of having two names for the same entity, I want the definitions proper of the module to be duplicated: I want two separate MonadRW classes and two separate RWT transformers. Since the module integrates the MonadRW and RWT transformer with the mtl, I would then only need to lift the instances of the instantiated MonadRW classes through the other RWTs. I'm rather unfamiliar with Template Haskell, but it sounds like it might fit the bill. Although, if I recall correctly, instances and type declarations splicing are yet to be implemented in GHC? Does anyone have any advice how to do this? I'm envisioning some preprocessing. I'd like to know if someone has developed a tool for this already or if this path has been attempted. Thanks for your time, Nick PS - If this doesn't work out, I'm aware that I could use type-indexed products and coproducts to pull it off, but I think that would drastically reduce the number of people who could understand/maintain the code without having to learn such cool stuff.

Hello Nicolas, Friday, June 29, 2007, 9:07:38 PM, you wrote:
I'm rather unfamiliar with Template Haskell, but it sounds like it might fit the bill. Although, if I recall correctly, instances and type declarations splicing are yet to be implemented in GHC?
instances - definitely not. i've used TH to generate Show instances http://www.haskell.org/bz/th3.htm http://www.haskell.org/bz/thdoc.htm -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

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. The class is called MonadRW and the transformer is | called RWT. | | I find myself wishing I could import the same module twice, but | instead of having two names for the same entity, I want the | definitions proper of the module to be duplicated: I want two separate | MonadRW classes and two separate RWT transformers. Since the module | integrates the MonadRW and RWT transformer with the mtl, I would then | only need to lift the instances of the instantiated MonadRW classes | through the other RWTs. | | I'm rather unfamiliar with Template Haskell, but it sounds like it | might fit the bill. Although, if I recall correctly, instances and | type declarations splicing are yet to be implemented in GHC? | | Does anyone have any advice how to do this? I'm envisioning some | preprocessing. I'd like to know if someone has developed a tool for | this already or if this path has been attempted. Sounds familiar :-). I wrote some TH code to get "named" versions of the StateT monad transformer. Example usage:
{-# OPTIONS_GHC -fth #-} module Test where
import NamedStateT
data Settings = ...
$(namedStateT "Settings" $ Just $ ConT ''Settings)
q :: (MonadSettings m,MonadIO m) => m () q = do settings <- getSettings liftIO $ print settings
Notes: - The second argument to namedStateT is the type of the state. |Nothing| keeps it parameterised, like |StateT| itself. - The big comment shows the code that would be generated by a typical splicing, although the code may have been updated at some point without changing the example accordingly. - Not all instances and helper functions from Control.Monad.State are in there; |modify| seems to be missing, for instance. If you need any, I can add them (or you can do it yourself). - I just saw I also have a NamedReaderT module, but it has never been used, so it may not work. Yell if you think you can use it. Kind regards, Arie -- Familiarity with the Haskell language is assumed, but no prior experience with warm, fuzzy things is required.

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.)

Dave Bayer wrote:
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.)
Yeah, a class/phantom type approach now seems more natural. At the time, I had just learned about Template Haskell, and this problem seemed like a nice nail :-). The code works for me, so I never bothered to rewrite it. Greetings, Arie
participants (4)
-
Arie Peterson
-
Bulat Ziganshin
-
Dave Bayer
-
Nicolas Frisby