haskell - "takeWhile" within a list comprehension -
i have following:
[bla z|n<-[0..], let z = foo n, z < 42]
the thing is, want list comprehension end z < 42
fails, if takewhile. know refactor bunch of filters , maps, more elegant list comprehension.
what elegant way combine list comprehensions , takewhile?
since list comprehensions not allow this, have hacked bit using monad comprehensions , defining custom monad. outcome of following works:
example :: [int] example = tolist [1000 + n | n <- fromlist [0..] , _ <- nonstopguard (n > 1) , let z = 10*n , _ <- stopguard (z < 42) ] -- output: [1002,1003,1004]
the above works normal list comprehension, has 2 different kinds of guard. nonstopguard
works regular guard, except requiring bizarre syntax. stopguard
instead more: become false, stops further choices in previous generators (such <-[0..]
) considered.
the small library wrote shown below:
{-# language derivefunctor, monadcomprehensions #-} import control.monad import control.applicative data f = f [a] bool deriving (functor, show)
the bool
above stop bit, signaling must stop considering further choices.
instance applicative f pure = return; (<*>) = ap instance monad f return x = f [x] false f [] s >>= _ = f [] s f (x:xs) sx >>= f = f (ys ++ zs) (sx || sy || sz) f ys sy = f x f zs sz = if sy f [] false else f xs sx >>= f
the last if
discard xs
part when f x
signals stop.
nonstopguard :: bool -> f () nonstopguard true = f [()] false nonstopguard false = f [] false
a regular guard never signals stop. provides 1 or 0 choices.
stopguard :: bool -> f () stopguard true = f [()] false stopguard false = f [] true
a stopping guard instead signals stop becomes false.
fromlist :: [a] -> f fromlist xs = f xs false tolist :: f -> [a] tolist (f xs _) = xs
last caveat: i'm not sure monad instance defines actual monad, i.e. whether satisfies monad laws.
following suggestion of @icktoofay, wrote few quickcheck tests:
instance arbitrary => arbitrary (f a) arbitrary = f <$> arbitrary <*> arbitrary instance show (a -> b) show _ = "function" prop_monadright :: f int -> bool prop_monadright m = (m >>= return) == m prop_monadleft :: int -> (int -> f int) -> bool prop_monadleft x f = (return x >>= f) == f x prop_monadassoc :: f int -> (int -> f int) -> (int -> f int) -> bool prop_monadassoc m f g = ((m >>= f) >>= g) == (m >>= (\x -> f x >>= g))
running 100000 tests found no counterexamples. so, it's above f
actual monad.
Comments
Post a Comment