packages feed

capped-list (empty) → 1.0

raw patch · 5 files changed

+322/−0 lines, 5 filesdep +basesetup-changed

Dependencies added: base

Files

+ Data/CappedList.hs view
@@ -0,0 +1,169 @@+-----------------------------------------------------------------------------+-- |+-- Module      :  Data.CappedList+-- Copyright   :  (c) 2010 John Millikin+-- License     :  BSD3+--+-- Maintainer  :  jmillikin@gmail.com+-- Portability :  portable+--+-- A list-like type for lazy sequences, with a user-defined termination value.+--+-- This module uses common names and so is designed to be imported qualified:+--+-- > import qualified Data.CappedList as CL+--+-----------------------------------------------------------------------------++module Data.CappedList+	( CappedList (..)+	, null+	, append+	, map+	, mapEither+	, concatMap+	, foldr+	, foldl+	, unfoldr+	, length+	) where+import Prelude hiding (null, map, concatMap, foldl, foldr, length)+import qualified Prelude as Prelude+import Data.Monoid (Monoid, mempty, mappend)+import Control.Monad (MonadPlus, mzero, mplus, ap)+import Control.Monad.Fix (MonadFix, fix, mfix)+import qualified Control.Applicative as A+import Control.Applicative ((<$>), (<*>))+import Data.Empty (Empty (empty))+import qualified Data.Foldable as F+import qualified Data.Traversable as T++-- | A list-like type for lazy sequences, with a user-defined termination value.+--+data CappedList cap a+	= Next a (CappedList cap a)+	| Cap cap+	deriving (Eq, Show)++-- TODO: deriving Data?++instance Empty cap => Empty (CappedList cap a) where+	empty = Cap empty++instance Functor (CappedList cap) where+	fmap = map++instance Empty cap => Monoid (CappedList cap a) where+	mempty = Cap empty+	mappend = append++instance Empty cap => Monad (CappedList cap) where+	Cap x       >>= _ = Cap x+	(Next x xs) >>= k = append (k x) (xs >>= k)+	return = flip Next (Cap empty)++instance Empty cap => MonadPlus (CappedList cap) where+	mzero = Cap empty+	mplus = append++instance Empty cap => A.Alternative (CappedList cap) where+	empty = Cap empty+	(<|>) = append++instance Empty cap => A.Applicative (CappedList cap) where+	pure = flip Next (Cap empty)+	(<*>) = ap++instance F.Foldable (CappedList cap) where+	foldMap = T.foldMapDefault++instance T.Traversable (CappedList cap) where+	sequenceA (Cap x)     = A.pure $ Cap x+	sequenceA (Next f fs) = Next <$> f <*> T.sequenceA fs++instance Empty cap => MonadFix (CappedList cap) where+	mfix f = case fix (f . head') of+		Cap x      -> Cap x+		(Next x _) -> append (return x) (mfix (tail' . f))++-- | Like the standard 'Prelude.null' function.+--+null :: CappedList cap a -> Bool+null (Next _ _) = False+null _          = True++-- | Like the standard '++' function.+--+append :: CappedList cap a -> CappedList cap a -> CappedList cap a+append x@(Cap _)   _ = x+append (Next x xs) y = Next x (append xs y)++-- | Like the standard 'Prelude.map' function.+--+map :: (a -> b) -> CappedList cap a -> CappedList cap b+map f = foldr (Next . f) Cap++{-# INLINE [1] map #-}++{-# RULES+  "map/map" forall f g t.+   map f (map g t) = map (f . g) t+  #-}++-- | Like the standard 'Prelude.map' function, but the mapping function may+-- return a capping value.+--+mapEither :: (a -> Either cap b) -> CappedList cap a -> CappedList cap b+mapEither f = foldr (\a acc -> either Cap (flip Next acc) (f a)) Cap++{-# INLINE [1] mapEither #-}++{-# RULES+  "mapEither/mapEither" forall f g t.+   mapEither f (mapEither g t) = mapEither (either Left g . f) t+  #-}++-- | Like the standard 'Prelude.concatMap' function.+--+concatMap :: (a -> CappedList cap b) -> CappedList cap a -> CappedList cap b+concatMap f = foldr (append . f) Cap++-- | Like the standard 'Prelude.foldr' function, but accepting an extra+-- parameter to handle 'Cap' values.+--+foldr :: (a -> b -> b) -> (cap -> b) -> CappedList cap a -> b+foldr f z = foldr' where+	foldr' (Cap x)     = z x+	foldr' (Next x xs) = f x (foldr' xs)++-- | Like the standard 'Prelude.foldl' function, but accepting an extra+-- parameter to handle 'Cap' values.+--+foldl :: (b -> a -> b) -> (cap -> b) -> CappedList cap a -> b+foldl f = foldl' where+	foldl' z (Cap x)     = z x+	foldl' z (Next x xs) = foldl' (\cap -> f (z cap) x) xs++-- | Like the standard 'Data.List.unfoldr' function, but the step function+-- must return a cap to terminate the unfold.+--+unfoldr :: (b -> Either cap (a, b)) -> b -> CappedList cap a+unfoldr f = unfoldr' where+	unfoldr' x = case f x of+		Left cap -> Cap cap+		Right (a, b) -> Next a (unfoldr' b)++-- | Like the standard 'Prelude.length' function; 'Cap' is considered+-- 0-length.+--+length :: CappedList cap a -> Int+length = foldr (const (1 +)) (const 0)++-- Partial functions, used only to implement mfix; not exported+head' :: CappedList cap a -> a+head' (Cap _)    = error "mfix CappedList: Cap"+head' (Next x _) = x++tail' :: CappedList cap a -> CappedList cap a+tail' (Cap _)     = error "mfix CappedList: Cap"+tail' (Next _ xs) = xs
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ Tests.hs view
@@ -0,0 +1,104 @@+-- Tests for Data.CappedList++module Main (tests) where+import Test.QuickCheck (Arbitrary, arbitrary)+import Test.Framework (Test, testGroup, defaultMain)+import Test.Framework.Providers.QuickCheck2 (testProperty)+import Data.CappedList (CappedList (..))+import qualified Data.CappedList as CL++main :: IO ()+main = defaultMain tests++tests :: [Test]+tests =+	[ testProperty "append" $ prop_Append+	, testProperty "map" $ prop_Map (1 +)+	, testProperty "mapEither Left" $ prop_MapEither (Left  . Just . (1 +))+	, testProperty "mapEither Right" $ prop_MapEither (Right . (1 +))+	, testProperty "concatMap" $ prop_ConcatMap (return . (1 +))+	, testProperty "foldr" $ prop_FoldR (+) $ \x -> case x of+		Nothing -> 0+		Just x -> x + 2+	, testProperty "foldl" $ prop_FoldL (+) $ \x -> case x of+		Nothing -> 0+		Just x -> x + 2+	, testProperty "unfoldr Left" $ prop_UnfoldR (Left . Just)+	, let+		step x = if x > 0+			then Right (x, x `div` 10)+			else Left (Just x)+		in testProperty "unfoldr Right" $ prop_UnfoldR step+	, testProperty "length" prop_Length+	]++instance (Arbitrary cap, Arbitrary a) => Arbitrary (CappedList cap a) where+	arbitrary = do+		cap <- arbitrary+		foldr Next (Cap cap) `fmap` arbitrary++-- Pseudo type variables, for polymorphic properties+type A = Int+type B = Int+type CAP = Maybe Int++prop_Length :: CappedList CAP A -> Bool+prop_Length fl = CL.length fl == modelLength fl++prop_Append :: CappedList CAP A -> CappedList CAP A -> Bool+prop_Append x y = CL.append x y == modelAppend x y++prop_Map :: (A -> B) -> CappedList CAP A -> Bool+prop_Map f fl = CL.map f fl == modelMap f fl++prop_MapEither :: (A -> Either CAP B) -> CappedList CAP A -> Bool+prop_MapEither f fl = CL.mapEither f fl == modelMapEither f fl++prop_FoldR :: (A -> B -> B) -> (CAP -> B) -> CappedList CAP A -> Bool+prop_FoldR f z fl = CL.foldr f z fl == modelFoldR f z fl++prop_FoldL :: (B -> A -> B) -> (CAP -> B) -> CappedList CAP A -> Bool+prop_FoldL f z fl = CL.foldl f z fl == modelFoldL f z fl++prop_UnfoldR :: (B -> Either CAP (A, B)) -> B -> Bool+prop_UnfoldR f nil = CL.unfoldr f nil == modelUnfoldR f nil++prop_ConcatMap :: (A -> CappedList CAP B) -> CappedList CAP A -> Bool+prop_ConcatMap f fl = CL.concatMap f fl == modelConcatMap f fl++-- Versions of the basic operations, inefficient but known to be correct.+modelLength :: CappedList cap a -> Int+modelLength (Cap _)     = 0+modelLength (Next x xs) = 1 + modelLength xs++modelAppend :: CappedList cap a -> CappedList cap a -> CappedList cap a+modelAppend (Cap x)     _ = Cap x+modelAppend (Next x xs) y = Next x (modelAppend xs y)++modelMap :: (a -> b) -> CappedList cap a -> CappedList cap b+modelMap _ (Cap x)     = Cap x+modelMap f (Next x xs) = Next (f x) (modelMap f xs)++modelMapEither :: (a -> Either cap b) -> CappedList cap a -> CappedList cap b+modelMapEither _ (Cap x) = Cap x+modelMapEither f (Next x xs) = case f x of+	Left cap -> Cap cap+	Right x' -> Next x' (modelMapEither f xs)++modelConcatMap :: (a -> CappedList cap b) -> CappedList cap a -> CappedList cap b+modelConcatMap _ (Cap x)     = Cap x+modelConcatMap f (Next x xs) = modelAppend (f x) (modelConcatMap f xs)++modelFoldR :: (a -> b -> b) -> (cap -> b) -> CappedList cap a -> b+modelFoldR _ z (Cap x)     = z x+modelFoldR f z (Next x xs) = f x (modelFoldR f z xs)++modelFoldL :: (b -> a -> b) -> (cap -> b) -> CappedList cap a -> b+modelFoldL _ z (Cap x)     = z x+modelFoldL f z (Next x xs) = modelFoldL f (\cap -> f (z cap) x) xs++modelUnfoldR :: (b -> Either cap (a, b)) -> b -> CappedList cap a+modelUnfoldR f = unfoldr' where+	unfoldr' x = case f x of+		Left cap -> Cap cap+		Right (a, b) -> Next a (unfoldr' b)
+ capped-list.cabal view
@@ -0,0 +1,21 @@+name: capped-list+version: 1.0+synopsis: A list-like type for lazy sequences, with a user-defined termination value.+license: BSD3+license-File: license.txt+author: John Millikin <jmillikin@gmail.com>+maintainer: John Millikin <jmillikin@gmail.com>+copyright: 2010 John Millikin <jmillikin@gmail.com>+build-type: Simple+cabal-version: >=1.2+category: Data+extra-source-files:+  Tests.hs++library+  build-depends: base >= 2 && < 5++  exposed-modules:+    Data.CappedList++  ghc-options: -Wall
+ license.txt view
@@ -0,0 +1,26 @@+Copyright (c) 2010 John Millikin+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 names of the copyright owners nor the names of the +  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.