Skip to content

Instantly share code, notes, and snippets.

@AndrasKovacs
Last active August 29, 2015 13:55
Show Gist options
  • Save AndrasKovacs/8784437 to your computer and use it in GitHub Desktop.
Save AndrasKovacs/8784437 to your computer and use it in GitHub Desktop.
My shot at ListT done right.
{-# 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