different function implementations for different values of typevar - is it possible?

Hi all. I am writing a Monad intace for my own Writer-like data type "HtmlWriter" (see code below). The main HtmlWriter's difference is in return() function. I'd like it to convert user data (a) to html. But here come troubles. In general, there are two cases: 1) (HTML a) exists 2) (HTML a) doesn't exist So, i need to write different implementations of return() for both cases. Something like this: 1) return a = HtmlWriter (a, toHtml a) 2) return a = HtmlWriter (a, toHtml (show a)) I can't find a way to do it. Is it possible somehow? Please, help. Here is the code: ------------- import Control.Monad import Text.XHtml.Transitional newtype HtmlWriter a = HtmlWriter { runHtmlWriter :: (a, Html) } instance Monad (HtmlWriter) where return a = HtmlWriter (a, toHtml a) -- ??? return a = HtmlWriter (a, toHtml (show a)) m >>= k = HtmlWriter $ let (a, w) = runHtmlWriter m (b, w') = runHtmlWriter (k a) in (b, w `mappend` w') ------- Thanks, Sergey.

Hi Sergey Are you sure you always want return to write as well? 'return' for the standard' MTL writer monad produces _a_ within the monad, but does no "writing": instance (Monoid w) => Monad (Writer w) where return a = Writer (a, mempty) m >>= k = Writer $ let (a, w) = runWriter m (b, w') = runWriter (k a) in (b, w `mappend` w') Text.XHtml.Transitional has the noHtml function which would be the analogue to mempty. Best wishes Stephen

2010/1/24 Stephen Tetley
Hi Sergey
Are you sure you always want return to write as well?
'return' for the standard' MTL writer monad produces _a_ within the monad, but does no "writing":
instance (Monoid w) => Monad (Writer w) where return a = Writer (a, mempty) m >>= k = Writer $ let (a, w) = runWriter m (b, w') = runWriter (k a) in (b, w `mappend` w')
Text.XHtml.Transitional has the noHtml function which would be the analogue to mempty.
Best wishes
Stephen
Mmm, yes.. it is not what i want actually. Seems, that my return-with-writing will break monad laws from "Real world Haskell". Now its clear, that i should use simple Writer Html (). Now code looks like: nested :: (Html -> Html) -> (Writer Html ()) -> Html nested a x = a << ( execWriter $ x ) buildPage :: Writer Html () buildPage = do tell $ header `nested` do tell $ meta ! [ strAttr "http-equiv" "Content-Type", strAttr "content" "text/html", strAttr "http-equiv" "text/html; charset=UTF-8" ] tell $ thetitle << "PageTitle" tell $ css_link ! [ href "css/blueprint/screen.css", media "screen, projection"] tell $ css_link ! [ href "css/blueprint/print.css", media "print"] tell $ css_link ! [ href "css/custom.css" ] tell $ body `nested` do tell $ noHtml -- ... and so on Thanks for warnings! -- Sergey

Hi Sergey Further... The writer monad is accompanied by a function 'tell' that is called explicitly to produce output. 'tell' is the 'non-proper morphism' of the writer monad (well the standard Monad Transformer Library - MTL version has a couple of other functions but that's an implementation detail). It characterizes the writer monad in the same way that 'ask' characterises the reader monad and the combination of get & put characterise the state monad. In Haskell, you have to represent a Monad with a data type or newtype - non-proper morphisms need to 'unpeel' the constructor to access the internals of the monad. Here is the code from MTL for Writers tell: instance (Monoid w) => MonadWriter w (Writer w) where tell w = Writer ((), w) ... (listen and pass - the other non-proper morphisms). Non-proper morphisms contrast with general monadic functions that are usable with any monad. Take liftM as an example - liftM needs only (>>=) and 'return' it doesn't have to look inside a monad's constructor: -- | Promote a function to a monad. liftM :: (Monad m) => (a1 -> r) -> m a1 -> m r liftM f m1 = do { x1 <- m1; return (f x1) } -- aka. liftM f m1 = m1 >>= \x1 -> return (f x1) You would want to add a 'tell' function to your module. You're not obliged to call it 'tell' of course, the MonadLib library, which is an alternative to the standard MTL library, calls the function 'put'. Best wishes Stephen
participants (2)
-
Sergey Mironov
-
Stephen Tetley