Last active
August 29, 2015 13:55
-
-
Save AndrasKovacs/8784437 to your computer and use it in GitHub Desktop.
My shot at ListT done right.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{-# LANGUAGE LambdaCase, DeriveFunctor #-} | |
import Prelude hiding (take, head) | |
import Control.Monad | |
import Control.Monad.Trans | |
data ListT' m a = Nil | Cons a (ListT m a) deriving (Functor) | |
newtype ListT m a = ListT {runListT :: m (ListT' m a)} deriving (Functor) | |
instance Monad m => Monad (ListT m) where | |
return a = ListT (return (Cons a mzero)) | |
xs >>= f = ListT $ | |
runListT xs >>= \case | |
Cons x xs -> runListT $ mplus (f x) (xs >>= f) | |
Nil -> return Nil | |
instance Monad m => MonadPlus (ListT m) where | |
mzero = ListT (return Nil) | |
mplus as bs = ListT $ | |
runListT as >>= \case | |
Cons a as -> return $ Cons a (mplus as bs) | |
Nil -> runListT bs | |
instance MonadTrans ListT where | |
lift = ListT . liftM (`Cons` mzero) | |
instance MonadIO m => MonadIO (ListT m) where | |
liftIO = lift . liftIO | |
choice :: Monad m => [a] -> ListT m a | |
choice = foldr (\x -> ListT . return . Cons x) mzero | |
take :: Monad m => Int -> ListT m a -> m [a] | |
take n l | n < 1 = return [] | |
take n l = runListT l >>= \case | |
Cons x xs -> liftM (x:) (take (n - 1) xs) | |
Nil -> return [] | |
-- unsafe head | |
head :: Monad m => ListT m a -> m a | |
head l = runListT l >>= \case | |
Cons x _ -> return x | |
_ -> error "head: empty ListT" | |
toList :: Monad m => ListT m a -> m [a] | |
toList l = runListT l >>= \case | |
Nil -> return [] | |
Cons x l -> liftM (x:) (toList l) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment