fmlist-0.9.4/0000755000000000000000000000000007346545000011213 5ustar0000000000000000fmlist-0.9.4/Data/0000755000000000000000000000000007346545000012064 5ustar0000000000000000fmlist-0.9.4/Data/FMList.hs0000644000000000000000000002120007346545000013551 0ustar0000000000000000----------------------------------------------------------------------------- -- | -- Module : Data.FMList -- Copyright : (c) Sjoerd Visscher 2009 -- License : BSD-style (see the file LICENSE) -- -- Maintainer : sjoerd@w3future.com -- Stability : experimental -- Portability : portable -- -- FoldMap lists: lists represented by their 'foldMap' function. -- -- Examples: -- -- > -- A right-infinite list -- > c = 1 `cons` c -- -- > -- A left-infinite list -- > d = d `snoc` 2 -- -- > -- A middle-infinite list ?? -- > e = c `append` d -- -- > *> head e -- > 1 -- > *> last e -- > 2 ----------------------------------------------------------------------------- {-# LANGUAGE CPP #-} {-# LANGUAGE RankNTypes #-} module Data.FMList ( FMList(..) , transform -- * Construction , empty , singleton , cons , snoc , pair , append , fromList , fromFoldable -- * Basic functions , null , length , genericLength , head , tail , last , init , reverse -- * Folding , toList , flatten , foldMapA , filter , take , drop , takeWhile , dropWhile , zip , zipWith -- * Unfolding , iterate , repeat , cycle , unfold , unfoldr ) where import Prelude ( (.), ($), ($!), flip, const, error , Either(..), either , Bool(..), (&&) , Ord(..), Num(..), Int , Show(..), String, (++) ) import Data.Maybe (Maybe(..), maybe, fromMaybe, isNothing) import Data.Monoid (Monoid, mempty, mappend, Dual(..), First(..), Last(..), Sum(..)) #if MIN_VERSION_base(4,9,0) import Data.Semigroup (Semigroup((<>))) #endif import Data.Foldable (Foldable, foldMap, foldr, toList) import Data.Traversable (Traversable, traverse) import Control.Monad import Control.Monad.Fail as MF import Control.Applicative -- | 'FMList' is a 'foldMap' function wrapped up in a newtype. -- newtype FMList a = FM { unFM :: forall m . Monoid m => (a -> m) -> m } -- | The function 'transform' transforms a list by changing -- the map function that is passed to 'foldMap'. -- -- It has the following property: -- -- @transform a . transform b = transform (b . a)@ -- -- For example: -- -- * @ m >>= g@ -- -- * @= flatten (fmap g m)@ -- -- * @= flatten . fmap g $ m@ -- -- * @= transform foldMap . transform (. g) $ m@ -- -- * @= transform ((. g) . foldMap) m@ -- -- * @= transform (\\f -> foldMap f . g) m@ -- transform :: (forall m. Monoid m => (a -> m) -> (b -> m)) -> FMList b -> FMList a transform t (FM l) = FM (l . t) -- shorthand constructors nil :: FMList a nil = FM mempty one :: a -> FMList a one x = FM ($ x) (><) :: FMList a -> FMList a -> FMList a FM l >< FM r = FM (l `mappend` r) -- exported constructors singleton :: a -> FMList a singleton = one cons :: a -> FMList a -> FMList a cons x l = one x >< l snoc :: FMList a -> a -> FMList a snoc l x = l >< one x pair :: a -> a -> FMList a pair l r = one l >< one r append :: FMList a -> FMList a -> FMList a append = (><) fromList :: [a] -> FMList a fromList = fromFoldable fromFoldable :: Foldable f => f a -> FMList a fromFoldable l = FM $ flip foldMap l mhead :: FMList a -> Maybe a mhead l = getFirst (unFM l (First . Just)) null :: FMList a -> Bool null = isNothing . mhead length :: FMList a -> Int length = genericLength genericLength :: Num b => FMList a -> b genericLength l = getSum $ unFM l (const $ Sum 1) head :: FMList a -> a head l = mhead l `fromMaybeOrError` "Data.FMList.head: empty list" tail :: FMList a -> FMList a tail l = if null l then error "Data.FMList.tail: empty list" else drop (1::Int) l last :: FMList a -> a last l = getLast (unFM l (Last . Just)) `fromMaybeOrError` "Data.FMList.last: empty list" init :: FMList a -> FMList a init l = if null l then error "Data.FMList.init: empty list" else reverse . drop (1::Int) . reverse $ l reverse :: FMList a -> FMList a reverse l = FM $ getDual . unFM l . (Dual .) flatten :: Foldable t => FMList (t a) -> FMList a flatten = transform foldMap filter :: (a -> Bool) -> FMList a -> FMList a filter p = transform (\f x -> if p x then f x else mempty) -- transform the foldMap to foldr with state. transformCS :: (forall m. Monoid m => (b -> m) -> a -> (m -> s -> m) -> s -> m) -> s -> FMList a -> FMList b transformCS t s0 l = FM $ \f -> foldr (\e r -> t f e (\a -> mappend a . r)) mempty l s0 take :: (Ord n, Num n) => n -> FMList a -> FMList a take = transformCS (\f e c i -> if i > 0 then c (f e) (i-1) else mempty) takeWhile :: (a -> Bool) -> FMList a -> FMList a takeWhile p = transformCS (\f e c _ -> if p e then c (f e) True else mempty) True drop :: (Ord n, Num n) => n -> FMList a -> FMList a drop = transformCS (\f e c i -> if i > 0 then c mempty (i-1) else c (f e) 0) dropWhile :: (a -> Bool) -> FMList a -> FMList a dropWhile p = transformCS (\f e c ok -> if ok && p e then c mempty True else c (f e) False) True zipWith :: (a -> b -> c) -> FMList a -> FMList b -> FMList c zipWith t = transformCS (\f e2 c r1 -> foldr (\e1 _ -> c (f (t e1 e2)) (drop (1::Int) r1)) mempty r1) zip :: FMList a -> FMList b -> FMList (a,b) zip = zipWith (,) iterate :: (a -> a) -> a -> FMList a iterate f x = x `cons` iterate f (f x) -- | 'repeat' buids an infinite list of a single value. -- While infinite, the result is still accessible from both the start and end. repeat :: a -> FMList a repeat = cycle . one -- | 'cycle' repeats a list to create an infinite list. -- It is also accessible from the end, where @last (cycle l)@ equals @last l@. cycle :: FMList a -> FMList a cycle l = l >< cycle l >< l -- | 'unfoldr' builds an 'FMList' from a seed value from left to right. -- The function takes the element and returns 'Nothing' -- if it is done producing the list or returns 'Just' @(a,b)@, in which -- case, @a@ is a appended to the result and @b@ is used as the next -- seed value in a recursive call. -- -- A simple use of 'unfoldr': -- -- > *> unfoldr (\b -> if b == 0 then Nothing else Just (b, b-1)) 10 -- > fromList [10,9,8,7,6,5,4,3,2,1] -- unfoldr :: (b -> Maybe (a, b)) -> b -> FMList a unfoldr g = unfold (maybe empty (\(a, b) -> Right a `pair` Left b) . g) -- | 'unfold' builds a list from a seed value. -- The function takes the seed and returns an 'FMList' of values. -- If the value is 'Right' @a@, then @a@ is appended to the result, and if the -- value is 'Left' @b@, then @b@ is used as seed value in a recursive call. -- -- A simple use of 'unfold' (simulating unfoldl): -- -- > *> unfold (\b -> if b == 0 then empty else Left (b-1) `pair` Right b) 10 -- > fromList [1,2,3,4,5,6,7,8,9,10] -- unfold :: (b -> FMList (Either b a)) -> b -> FMList a unfold g = transform (\f -> either (foldMap f . unfold g) f) . g newtype WrapApp f m = WrapApp { unWrapApp :: f m } #if MIN_VERSION_base(4,9,0) instance (Applicative f, Semigroup m) => Semigroup (WrapApp f m) where WrapApp a <> WrapApp b = WrapApp $ (<>) <$> a <*> b #endif instance (Applicative f, Monoid m) => Monoid (WrapApp f m) where mempty = WrapApp $ pure mempty mappend (WrapApp a) (WrapApp b) = WrapApp $ mappend <$> a <*> b -- | Map each element of a structure to an action, evaluate these actions from left to right, -- and concat the monoid results. foldMapA :: (Foldable t, Applicative f, Monoid m) => (a -> f m) -> t a -> f m foldMapA f = unWrapApp . foldMap (WrapApp . f) instance Functor FMList where fmap g = transform (\f -> f . g) a <$ l = transform (\f -> const (f a)) l instance Foldable FMList where foldMap m f = unFM f m instance Traversable FMList where traverse f = foldMapA (fmap one . f) instance Monad FMList where return = one m >>= g = transform (\f -> foldMap f . g) m m >> k = transform (\f -> const (foldMap f k)) m instance MF.MonadFail FMList where fail _ = nil instance Applicative FMList where pure = one gs <*> xs = transform (\f g -> unFM xs (f . g)) gs as <* bs = transform (\f a -> unFM bs (const (f a))) as as *> bs = transform (\f -> const (unFM bs f)) as #if MIN_VERSION_base(4,9,0) instance Semigroup (FMList a) where (<>) = (><) #endif instance Monoid (FMList a) where mempty = nil mappend = (><) instance MonadPlus FMList where mzero = nil mplus = (><) instance Alternative FMList where empty = nil (<|>) = (><) instance Show a => Show (FMList a) where show l = "fromList " ++ (show $! toList l) fromMaybeOrError :: Maybe a -> String -> a fromMaybeOrError ma e = fromMaybe (error e) ma fmlist-0.9.4/LICENSE0000644000000000000000000000276407346545000012231 0ustar0000000000000000Copyright Sjoerd Visscher 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 Sjoerd Visscher 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. fmlist-0.9.4/Setup.lhs0000644000000000000000000000011407346545000013017 0ustar0000000000000000#!/usr/bin/env runhaskell > import Distribution.Simple > main = defaultMain fmlist-0.9.4/fmlist.cabal0000644000000000000000000000173007346545000013476 0ustar0000000000000000name: fmlist version: 0.9.4 synopsis: FoldMap lists description: FoldMap lists are lists represented by their foldMap function. FoldMap lists have O(1) cons, snoc and append, just like DLists, but other operations might have favorable performance characteristics as well. These wild claims are still completely unverified though. category: Data license: BSD3 license-file: LICENSE author: Sjoerd Visscher maintainer: sjoerd@w3future.com homepage: https://github.com/sjoerdvisscher/fmlist bug-reports: https://github.com/sjoerdvisscher/fmlist/issues build-type: Simple cabal-version: >= 1.10 Library exposed-modules: Data.FMList build-depends: base >= 3 && < 5 if impl(ghc < 8.0) build-depends: fail default-language: Haskell98 source-repository head type: git location: git://github.com/sjoerdvisscher/fmlist.git