packages feed

List (empty) → 0.1

raw patch · 5 files changed

+437/−0 lines, 5 filesdep +basedep +mtlsetup-changed

Dependencies added: base, mtl

Files

+ LICENSE view
@@ -0,0 +1,32 @@+Copyright Yair Chuchem 2009.++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are+met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Yair Chuchem nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.+
+ List.cabal view
@@ -0,0 +1,24 @@+Name:                List+Version:             0.1+Category:            Control+Synopsis:            List monad transformer and class+Description:+    A List monad transformer and a List class.+    With standard list operations for Lists+License:             BSD3+License-file:        LICENSE+Author:              Yair Chuchem+Maintainer:          yairchu@gmail.com+Homepage:            http://github.com/yairchu/generator/tree+Cabal-Version:       >= 1.2+Stability:           experiemental+Build-type:          Simple++Library+  hs-Source-Dirs:      src+  Extensions:+  Build-Depends:       base >= 3 && < 5, mtl+  Exposed-modules:     Control.Monad.ListT,+                       Data.List.Class+  Ghc-Options:         -O2 -Wall+
+ Setup.hs view
@@ -0,0 +1,3 @@+import Distribution.Simple+main = defaultMain+
+ src/Control/Monad/ListT.hs view
@@ -0,0 +1,112 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, UndecidableInstances #-}++-- Module is called ListT because List is taken by mtl++-- | A list monad transformer / a monadic list.+--+-- Monadic list example:+--   A program which reads numbers from the user and accumulates them.+--+-- > import Control.Monad.ListT (ListT)+-- > import Data.List.Class (execute, joinM, repeat, scanl, takeWhile)+-- > import Prelude hiding (repeat, scanl, takeWhile)+-- >+-- > main =+-- >   execute . joinM . fmap print .+-- >   scanl (+) 0 .+-- >   fmap (fst . head) .+-- >   takeWhile (not . null) .+-- >   fmap reads .+-- >   joinM $ (repeat getLine :: ListT IO (IO String))++module Control.Monad.ListT (+  ListItem(..), ListT(..), foldrListT+) where++import Control.Applicative (Applicative(..))+import Control.Monad (MonadPlus(..), ap, liftM)+-- import Control.Monad.Cont.Class (MonadCont(..))+import Control.Monad.Error.Class (MonadError(..))+import Control.Monad.Reader.Class (MonadReader(..))+import Control.Monad.State.Class (MonadState(..))+import Control.Monad.Trans (MonadTrans(..), MonadIO(..))+import Data.Monoid (Monoid(..))++data ListItem l a =+  Nil |+  Cons { headL :: a, tailL :: l a }++newtype ListT m a = ListT { runListT :: m (ListItem (ListT m) a) }++-- | foldr for ListT+foldrListT :: Monad m => (a -> m b -> m b) -> m b -> ListT m a -> m b+foldrListT consFunc nilFunc list = do+  item <- runListT list+  case item of+    Nil -> nilFunc+    Cons x xs -> consFunc x $ foldrListT consFunc nilFunc xs++-- for mappend, fmap, bind+foldrListT' :: Monad m =>+  (a -> ListT m b -> ListT m b) -> ListT m b -> ListT m a -> ListT m b+foldrListT' consFunc nilFunc =+  ListT . foldrListT step (runListT nilFunc)+  where+    step x = runListT . consFunc x . ListT++-- like generic cons except using that one+-- would cause an infinite loop+cons :: Monad m => a -> ListT m a -> ListT m a+cons x = ListT . return . Cons x++instance Monad m => Monoid (ListT m a) where+  mempty = ListT $ return Nil+  mappend = flip (foldrListT' cons)++instance Monad m => Functor (ListT m) where+  fmap func = foldrListT' (cons . func) mempty++instance Monad m => Monad (ListT m) where+  return = ListT . return . (`Cons` mempty)+  a >>= b = foldrListT' mappend mempty $ fmap b a++instance Monad m => Applicative (ListT m) where+  pure = return+  (<*>) = ap++instance Monad m => MonadPlus (ListT m) where+  mzero = mempty+  mplus = mappend++instance MonadTrans ListT where+  lift = ListT . liftM (`Cons` mempty)++-- YUCK:+-- I can't believe I'm doing this,+-- for compatability with mtl's ListT.+-- I hate the O(N^2) code length auto-lifts. DRY!!++instance MonadIO m => MonadIO (ListT m) where+  liftIO = lift . liftIO++{-+-- TODO: understand and verify this instance :)+instance MonadCont m => MonadCont (ListT m) where+  callCC f =+    ListT $ callCC thing+    where+      thing c = runListT . f $ ListT . c . (`Cons` mempty)+-}++instance MonadError e m => MonadError e (ListT m) where+  throwError = lift . throwError+  catchError m = ListT . catchError (runListT m) . (runListT .)++instance MonadReader s m => MonadReader s (ListT m) where+  ask = lift ask+  local f = ListT . local f . runListT++instance MonadState s m => MonadState s (ListT m) where+  get = lift get+  put = lift . put+
+ src/Data/List/Class.hs view
@@ -0,0 +1,266 @@+{-# LANGUAGE FlexibleContexts, RankNTypes, TypeFamilies #-}++-- | The 'List' class and actions for lists++module Data.List.Class (+  -- | The List typeclass+  List (..),+  -- | List operations for MonadPlus+  cons, fromList, filter, repeat,+  -- | Standard list operations+  takeWhile, genericTake, scanl,+  transpose, zip, zipWith,+  -- | Non standard List operations+  foldlL, toList, lengthL, lastL,+  merge2On, mergeOn,+  -- | Operations useful for monadic lists+  execute, joinM,+  -- | Convert between List types+  convList, transformListMonad, liftListMonad+  ) where++import Control.Monad (MonadPlus(..), ap, join, liftM)+import Control.Monad.Identity (Identity(..))+import Control.Monad.ListT (ListT(..), ListItem(..), foldrListT)+import Control.Monad.Trans (MonadTrans(..))+import Data.Function (fix)+import Prelude hiding (+  filter, repeat, scanl, takeWhile, zip, zipWith)++-- | A class for list types.+-- Every list has an underlying monad.+class (MonadPlus l, Monad (ItemM l)) => List l where+  type ItemM l :: * -> *+  -- | Transform an action returning a list to the returned list+  --+  -- > > joinL $ Identity "hello"+  -- > "hello"+  joinL :: ItemM l (l b) -> l b+  -- | foldr for 'List's.+  -- the result and 'right side' values are monadic actions.+  foldrL :: (a -> ItemM l b -> ItemM l b) -> ItemM l b -> l a -> ItemM l b+  foldrL consFunc nilFunc = foldrL consFunc nilFunc . toListT+  -- | Convert to a 'ListT'.+  --+  -- Can be done with a foldrL but included in type-class for efficiency.+  toListT :: l a -> ListT (ItemM l) a+  toListT = convList+  -- | Convert from a 'ListT'.+  --+  -- Can be done with a foldrL but included in type-class for efficiency.+  fromListT :: ListT (ItemM l) a -> l a+  fromListT = convList++instance List [] where+  type ItemM [] = Identity+  joinL = runIdentity+  foldrL = foldr+  toListT = fromList++instance Monad m => List (ListT m) where+  type ItemM (ListT m) = m+  joinL = ListT . (>>= runListT)+  foldrL = foldrListT+  toListT = id+  fromListT = id++-- | Prepend an item to a 'MonadPlus'+cons :: MonadPlus m => a -> m a -> m a+cons = mplus . return++-- | Convert a list to a 'MonadPlus'+--+-- > > fromList [] :: Maybe Int+-- > Nothing+-- > > fromList [5] :: Maybe Int+-- > Just 5+fromList :: MonadPlus m => [a] -> m a+fromList = foldr (mplus . return) mzero++-- | Convert between lists with the same underlying monad+convList :: (ItemM l ~ ItemM k, List l, List k) => l a -> k a+convList =+  joinL . foldrL step (return mzero)+  where+    step x = return . cons x . joinL++-- | filter for any MonadPlus+--+-- > > filter (> 5) (Just 3)+-- > Nothing+filter :: MonadPlus m => (a -> Bool) -> m a -> m a+filter cond =+  (>>= f)+  where+    f x+      | cond x = return x+      | otherwise = mzero++-- for foldlL and scanl+foldlL' :: List l =>+  (a -> (ItemM l) c -> c) -> (a -> c) ->+  (a -> b -> a) -> a -> l b -> c+foldlL' joinVals atEnd step startVal =+  t startVal . foldrL astep (return atEnd)+  where+    astep x rest = return $ (`t` rest) . (`step` x)+    t cur = joinVals cur . (`ap` return cur)++-- | An action to do foldl for 'List's+foldlL :: List l => (a -> b -> a) -> a -> l b -> ItemM l a+foldlL step startVal =+  foldlL' (const join) id astep (return startVal)+  where+    astep rest x = liftM (`step` x) rest++scanl :: List l => (a -> b -> a) -> a -> l b -> l a+scanl =+  foldlL' consJoin $ const mzero+  where+    consJoin cur = cons cur . joinL++genericTake :: (Integral i, List l) => i -> l a -> l a+genericTake count+  | count <= 0 = const mzero+  | otherwise = foldlL' joinStep (const mzero) next Nothing+  where+    next Nothing x = Just (count, x)+    next (Just (i, _)) y = Just (i - 1, y)+    joinStep Nothing = joinL+    joinStep (Just (1, x)) = const $ return x+    joinStep (Just (_, x)) = cons x . joinL++-- | Execute the monadic actions in a 'List'+execute :: List l => l a -> ItemM l ()+execute = foldlL const ()++-- | Transform a list of actions to a list of their results+--+-- > > joinM [Identity 4, Identity 7]+-- > [4,7]+joinM :: List l => l (ItemM l a) -> l a+joinM =+  joinL . foldrL consFunc (return mzero)+  where+    consFunc action rest = do+      x <- action+      return . cons x . joinL $ rest++takeWhile :: List l => (a -> Bool) -> l a -> l a+takeWhile cond =+  joinL . foldrL step (return mzero)+  where+    step x+      | cond x = return . cons x . joinL+      | otherwise = const $ return mzero++-- | An action to transform a 'List' to a list+--+-- > > runIdentity $ toList "hello!"+-- > "hello!"+toList :: List l => l a -> ItemM l [a]+toList =+  foldrL step $ return []+  where+    step = liftM . (:)++-- | Consume a list (execute its actions) and return its length+--+-- > > runIdentity $ lengthL [1,2,3]+-- > 3+lengthL :: (Integral i, List l) => l a -> ItemM l i+lengthL = foldlL (const . (+ 1)) 0++-- | Transform the underlying monad of a list given a way to transform the monad+--+-- > > import Data.List.Tree (bfs)+-- > > bfs (transformListMonad (\(Identity x) -> [x, x]) "hey" :: ListT [] Char)+-- > "hheeeeyyyyyyyy"+transformListMonad :: (List l, List k) =>+  (forall x. ItemM l x -> ItemM k x) -> l a -> k a+transformListMonad trans =+  t . foldrL step (return mzero)+  where+    t = joinL . trans+    step x = return . cons x . t++-- | Lift the underlying monad of a list and transform it to a ListT.+--+-- Doing plain 'transformListMonad lift' instead doesn't give the compiler+-- the same knowledge about the types.+liftListMonad ::+  (MonadTrans t, Monad (t (ItemM l)), List l) =>+  l a -> ListT (t (ItemM l)) a+liftListMonad = transformListMonad lift++zip :: List l => l a -> l b -> l (a, b)+zip as bs =+  r0 (toListT as) (toListT bs)+  where+    r0 xx yy =+      joinL $ do+        xi <- runListT xx+        case xi of+          Nil -> return mzero+          Cons x xs -> r1 x xs yy+    r1 :: List l => a -> ListT (ItemM l) a -> ListT (ItemM l) b -> ItemM l (l (a, b))+    r1 x xs yy = do+      yi <- runListT yy+      return $ case yi of+        Nil -> mzero+        Cons y ys ->+          cons (x, y) $ r0 xs ys++-- zipWith based on zip and not vice versa,+-- because the other way around hlint compains "use zip".+zipWith :: List l => (a -> b -> c) -> l a -> l b -> l c+zipWith func as = liftM (uncurry func) . zip as++-- | Consume all items and return the last one+--+-- > > runIdentity $ lastL "hello"+-- > 'o'+lastL :: List l => l a -> ItemM l a+lastL = foldlL (const id) undefined++repeat :: MonadPlus m => a -> m a+repeat = fix . cons++transpose :: List l => l (l a) -> l (l a)+transpose matrix =+  joinL $ toList matrix >>= r . map toListT+  where+    r xs = do+      items <- mapM runListT xs+      return $ case filter isCons items of+        [] -> mzero+        citems ->+          cons (fromList (map headL citems)) .+          joinL . r $ map tailL citems+    isCons Nil = False+    isCons _ = True++-- | Merge many lists sorted by a criteria given the criteria+--+-- > > mergeOn length [["hi", "hey", "hello"], ["cat", "falcon"], ["banana", "cucumber"]]+-- > ["hi","cat","hey","hello","banana","falcon","cucumber"]+mergeOn :: (Ord b, List l) => (a -> b) -> l (l a) -> l a+mergeOn f = joinL . foldlL (merge2On f) mzero++-- | Merge two lists sorted by a criteria given the criteria+--+-- > > merge2On id "01568" "239"+-- > "01235689"+merge2On :: (Ord b, List l) => (a -> b) -> l a -> l a -> l a+merge2On f xx yy =+  fromListT . joinL $ do+    xi <- runListT (toListT xx)+    yi <- runListT (toListT yy)+    return $ case (xi, yi) of+      (Cons x xs, Cons y ys)+        | f y > f x -> cons x . merge2On f xs $ cons y ys+        | otherwise -> cons y $ merge2On f (cons x xs) ys+      (Cons x xs, Nil) -> cons x xs+      (Nil, Cons y ys) -> cons y ys+      (Nil, Nil) -> mzero+