--
You received this message because you are subscribed to the Google Groups "Bay Area Haskell Users Group" group.
To post to this group, send email to baha...@googlegroups.com.
To unsubscribe from this group, send email to bahaskell+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/bahaskell?hl=en.
(btw: i assume your splitWhen2 for Test 2 was a typo and you meant splitBetween?)
Here's what I came up with without first looking at your implementation:
splitBetween :: (a -> a -> Bool) -> [a] -> [[a]]
splitBetween f [] = []
splitBetween f xs@(x:_) = (x : map fst pre) : splitBetween f (map fst post)
where (pre, post) = break (\(x, y) -> f y x) (zip (drop 1 xs) xs)
I don't know if it's particularly better, but it seems to pass the
tests, and I can read it easier than the others. But of course I
would, since I wrote it :)
I have this function:
justm :: (Monad m) => m (Maybe a) -> (a -> m (Maybe b)) -> m (Maybe b)
justm op1 op2 = maybe (return Nothing) op2 =<< op1
It's used when I have a bunch of monadic operations that return
Maybes. However, what I really want is to layer on a MaybeT:
something :: (Monad m) => MyMonadT m (Maybe X)
something = Maybe.runMaybeT $ do
x <- op1
y <- op2 x
etc
Unfortunately without explicit lifting for 'op1' and 'op2' I can't do it:
Couldn't match expected type `MyMonadT m X'
against inferred type `Maybe.MaybeT m1 X'
Sticking lifts on everything is just about as much work as sticking
justms on everything. Now, I'm guessing I have to make some busywork
instances to do the automatic lifting, either on MyMonadT to
understand MaybeT or on MaybeT to understand MyMonadT. However, the
last time I wanted to do that I had to write a MyMonad class and then
everyone had to say '(MyMonad m) => m X' instead of '(Monad m) =>
MyMonadT m X'. But for some reason I can never keep all that
typeclass magic clear in my mind, so it's always lots of thrashing
around to get it to work, and if it involves changing a zillion
signatures... forget it.
This all makes me think it isn't worth the hassle and I should stick
with 'justm'. It's less elegant, but seems simpler and more
localized. This makes me wonder two things:
1 - Is the automatic lifting simpler than I think, and there's some
easy way to do it?
2 - Is there a way to generalize the 'justm' style of "monad
transformer"? Though I have a feeling like if I keep chasing that
tiger I'll just wind up with 'lift'.
3 - Why are monad transformers so hard? :P
So, 'justm', even though it feels wrong from the theory point of view,
is looking more right from the practical point of view.
If someone were designing a language that had transformers from the
beginning, how would this look different? You can't very well insist
that every Maybe function return '(Monad m) => MaybeT m' unless
there's syntax to actually make that reasonable as a default.
I'm not sure what you mean by "scans the length", since zip is lazy
and doesn't need to know the length of its arguments. However, what
mine does do is zip together the next element, then strip it off, then
zip it back on on the next call. So unless the compiler is being
clever, at the end of a long list, pulling an element off of the zip
is going to look like:
(x2, fst (x2, fst (x2, fst (x2, x1)))) ...
So I'm suggesting that this is the source of my version's
inefficiency. Unless I'm missing what you mean by "scans" up there?
Coincidentally, I just needed this very function to detect consecutive
runs, so I went back to fix my version. Removing the extra zips and
maps gives:
split_between :: (a -> a -> Bool) -> [a] -> [[a]]
split_between _ [] = []
split_between f xs = pre : split_between f post
where (pre, post) = break_between f xs
break_between :: (a -> a -> Bool) -> [a] -> ([a], [a])
break_between f (x1 : xs@(x2:_))
| f x1 x2 = ([x1], xs)
| otherwise = let (pre, post) = break_between f xs in (x1 : pre, post)
break_between _ xs = (xs, [])
This one seems to split up a 5000 element list in a more acceptable time.
Interestingly, I tend to think in breaks while Ivan seems to think in spans.
Eric:
Our solutions are similar, except yours returns a pair as [x, y] and
uses head and tail. I always get suspicious when I see partial
functions like that in use. Returning a real pair will let the
typechecker prove that it's safe, but it means you need a helper
function. It also gets rid of your pesky special cases, but mostly,
if you never use head and tail you'll never get the dreaded
"Prelude.head: empty list".
import Data.List
splitBetween p = groupBy (\x y -> not (p x y))
splitBetween :: (a -> a-> Bool) -> [a] -> [[a]]
That's it!