<span style="color: rgb(34, 34, 34); font-family: arial, sans-serif; font-size: 13px; background-color: rgb(255, 255, 255); ">Alright, I return from the land of transformers with a solution:</span><div style="color: rgb(34, 34, 34); font-family: arial, sans-serif; font-size: 13px; background-color: rgb(255, 255, 255); ">
<br></div><div style="color: rgb(34, 34, 34); font-family: arial, sans-serif; font-size: 13px; background-color: rgb(255, 255, 255); "><br></div><div style="color: rgb(34, 34, 34); font-family: arial, sans-serif; font-size: 13px; background-color: rgb(255, 255, 255); ">
import Control.Monad.Trans.Class</div><div style="color: rgb(34, 34, 34); font-family: arial, sans-serif; font-size: 13px; background-color: rgb(255, 255, 255); ">import Control.Monad.Trans.Maybe</div><div style="color: rgb(34, 34, 34); font-family: arial, sans-serif; font-size: 13px; background-color: rgb(255, 255, 255); ">
<br></div><div style="color: rgb(34, 34, 34); font-family: arial, sans-serif; font-size: 13px; background-color: rgb(255, 255, 255); ">main = sequenceMTAll (lst' >>= map (getB' >=> getC'))</div><div style="color: rgb(34, 34, 34); font-family: arial, sans-serif; font-size: 13px; background-color: rgb(255, 255, 255); ">
<br></div><div style="color: rgb(34, 34, 34); font-family: arial, sans-serif; font-size: 13px; background-color: rgb(255, 255, 255); "><div>lst' = lift lst :: MaybeT m [a]</div><div>getB' = MaybeT . getMB</div><div>
getC' = lift . getC</div></div><div style="color: rgb(34, 34, 34); font-family: arial, sans-serif; font-size: 13px; background-color: rgb(255, 255, 255); "><br></div><div style="color: rgb(34, 34, 34); font-family: arial, sans-serif; font-size: 13px; background-color: rgb(255, 255, 255); ">
<div>sequenceMTAll :: (Monad m) => [MaybeT m a] -> m [a]</div><div>sequenceMTAll (x:xs) = do</div><div> y <- runMaybeT x</div><div> case y of</div><div> Nothing -> sequenceMTAll xs</div><div> Just z -> sequenceMTAll xs >>= return . (z:)</div>
<div>sequenceMTAll [] = return []</div></div><div style="color: rgb(34, 34, 34); font-family: arial, sans-serif; font-size: 13px; background-color: rgb(255, 255, 255); "><br></div><div style="color: rgb(34, 34, 34); font-family: arial, sans-serif; font-size: 13px; background-color: rgb(255, 255, 255); ">
<br></div><div style="color: rgb(34, 34, 34); font-family: arial, sans-serif; font-size: 13px; background-color: rgb(255, 255, 255); ">(Of course in real code I'd just modify lst, getMB, getC, etc. to fit the new types. The crux here is sequenceMTAll.)</div>
<div style="color: rgb(34, 34, 34); font-family: arial, sans-serif; font-size: 13px; background-color: rgb(255, 255, 255); "><br></div><div style="color: rgb(34, 34, 34); font-family: arial, sans-serif; font-size: 13px; background-color: rgb(255, 255, 255); ">
Am I abusing Maybe too much?</div><div style="color: rgb(34, 34, 34); font-family: arial, sans-serif; font-size: 13px; background-color: rgb(255, 255, 255); "><br></div>Mike S Craig<br>(908) 328 8030<br>
<br><br><div class="gmail_quote">On Thu, Sep 15, 2011 at 1:15 AM, Brent Yorgey <span dir="ltr"><<a href="mailto:byorgey@seas.upenn.edu">byorgey@seas.upenn.edu</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<div class="im">On Wed, Sep 14, 2011 at 09:21:04PM -0400, Michael Craig wrote:<br>
> Brent: Thanks for reminding me about (>=>). Far more readable! But regarding<br>
> the sequence thing: I can think of all sorts of reasons why we'd want to do<br>
> a single traversal. How about when lst is long or infinite? In general, it's<br>
> more useful to produce output incrementally than all at once at the<br>
> end.<br>
<br>
</div>Yes, producing output incrementally is great! My point is that<br>
usually laziness will take care of it for you, without having to<br>
worry about it specifically.<br>
<br>
In this particular case, most monads will not actually allow<br>
incremental processing anyway. For example, suppose m = Maybe. Then<br>
when mapping getMB over lst, any particular element could cause the<br>
whole computation to fail. So we cannot output anything based on the<br>
first elements in the list until we have processed the entire list,<br>
because until we get to the very end of the list we do not know<br>
whether to begin by outputting 'Just' or 'Nothing'.<br>
<font color="#888888"><br>
-Brent<br>
</font><div><div></div><div class="h5"><br>
><br>
> Mike S Craig<br>
> <a href="tel:%28908%29%20328%208030" value="+19083288030">(908) 328 8030</a><br>
><br>
><br>
> On Wed, Sep 14, 2011 at 8:18 PM, Brent Yorgey <<a href="mailto:byorgey@seas.upenn.edu">byorgey@seas.upenn.edu</a>>wrote:<br>
><br>
> > On Wed, Sep 14, 2011 at 06:48:29PM -0400, Michael Craig wrote:<br>
> > > Say we've got these types<br>
> > ><br>
> > > lst :: m [a]<br>
> > > getMB :: a -> m (Maybe b)<br>
> > > getC :: b -> m c<br>
> > ><br>
> > > and we want to map getMB and getC over the elements of lst, all the while<br>
> > > discarding elements x where getMB x == Nothing.<br>
> > ><br>
> > > (This could be generalized more by replacing Maybe with some monad m',<br>
> > but<br>
> > > let's run with Maybe because it's easy to talk about.)<br>
> > ><br>
> > > The best I've got (after some help on IRC) is this not-so-easy-to-read<br>
> > > oneliner:<br>
> > ><br>
> > > lst >>= (\x -> mapM (liftM (liftM getC) (getMB x)) >>= sequence<br>
> > > . catMaybes<br>
> ><br>
> > How about this:<br>
> ><br>
> > lst >>= (mapM getMB >=> (return . catMaybes) >=> mapM getC)<br>
> ><br>
> > Everyone always forgets about (>=>).<br>
> ><br>
> > > This is hard to read, but it's also bad because we run sequence twice<br>
> > (once<br>
> > > inside of mapM). If we want to do multiple things to each element of lst,<br>
> > it<br>
> > > would be nice to process each element completely before moving on to the<br>
> > > next.<br>
> ><br>
> > I wouldn't worry about running sequence twice. Processing things by<br>
> > chaining whole-structure transformations is the Haskell Way (tm). All<br>
> > that business about "doing only one traversal" is for people<br>
> > programming in strict languages to worry about. The compiler can often<br>
> > turn a chain of wholesale transformations into a single traversal<br>
> > anyway. In short, I see no particular reason why it is "nice" to<br>
> > process each element completely before moving on. Isn't it nicer to<br>
> > be able to think in a more modular style?<br>
> ><br>
> > -Brent<br>
> ><br>
> > _______________________________________________<br>
> > Beginners mailing list<br>
> > <a href="mailto:Beginners@haskell.org">Beginners@haskell.org</a><br>
> > <a href="http://www.haskell.org/mailman/listinfo/beginners" target="_blank">http://www.haskell.org/mailman/listinfo/beginners</a><br>
> ><br>
</div></div></blockquote></div><br>