{-# LANGUAGE LiberalTypeSynonyms #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE BangPatterns #-} {-# LANGUAGE Rank2Types #-} ----------------------------------------------------------------------------- -- | -- Module : Data.List.Lens -- Copyright : (C) 2012 Edward Kmett -- License : BSD-style (see the file LICENSE) -- Maintainer : Edward Kmett -- Stability : provisional -- Portability : portable -- -- Traversals for manipulating parts of a list. -- ---------------------------------------------------------------------------- module Data.List.Lens ( -- * Partial Lenses _head , _tail , _last , _init -- * Traversals , traverseHead , traverseTail , traverseInit , traverseLast ) where import Control.Applicative import Control.Lens -- | A partial 'Lens' reading and writing to the 'head' of a /non-empty/ list. -- -- Attempting to read or write to the 'head' of an /empty/ list will result in an 'error'. -- -- >>> [1,2,3]^._head -- 1 _head :: Simple Lens [a] a _head _ [] = error "_head: empty list" _head f (a:as) = (:as) <$> f a {-# INLINE _head #-} -- | A partial 'Lens' reading and writing to the 'tail' of a /non-empty/ list -- -- Attempting to read or write to the 'tail' of an /empty/ list will result in an 'error'. -- -- >>> _tail .~ [3,4,5] $ [1,2] -- [1,3,4,5] _tail :: Simple Lens [a] [a] _tail _ [] = error "_tail: empty list" _tail f (a:as) = (a:) <$> f as {-# INLINE _tail #-} -- | A partial 'Lens' reading and writing to the last element of a /non-empty/ list -- -- Attempting to read or write to the last element of an /empty/ list will result in an 'error'. -- -- >>> [1,2]^._last -- 2 _last :: Simple Lens [a] a _last _ [] = error "_last: empty list" _last f [a] = return <$> f a _last f (a:as) = (a:) <$> _last f as {-# INLINE _last #-} -- | A partial 'Lens' reading and replacing all but the a last element of a /non-empty/ list -- -- Attempting to read or write to all but the last element of an /empty/ list will result in an 'error'. -- -- >>> [1,2,3,4]^._init -- [1,2,3] _init :: Simple Lens [a] [a] _init _ [] = error "_init: empty list" _init f as = (++ [Prelude.last as]) <$> f (Prelude.init as) {-# INLINE _init #-} -- | A traversal for reading and writing to the head of a list -- -- The position of the head in the original list (0) is available as the index. -- -- >>> traverseHead +~ 1 $ [1,2,3] -- [2,2,3] -- -- @'traverseHead' :: 'Applicative' f => (a -> f a) -> [a] -> f [a]@ traverseHead :: SimpleIndexedTraversal Int [a] a traverseHead = index $ \f aas -> case aas of [] -> pure [] (a:as) -> (:as) <$> f (0::Int) a {-# INLINE traverseHead #-} -- | A traversal for editing the tail of a list -- -- The position of each element /in the original list/ is available as the index. -- -- >>> traverseTail +~ 1 $ [1,2,3] -- [1,3,4] -- -- @'traverseTail' :: 'Applicative' f => (a -> f a) -> [a] -> f [a]@ traverseTail :: SimpleIndexedTraversal Int [a] a traverseTail = index $ \f aas -> case aas of [] -> pure [] (a:as) -> (a:) <$> itraverse (f . (+1)) as {-# INLINE traverseTail #-} -- | A traversal the last element in a list -- -- The position of the last element in the original list is available as the index. -- -- >>> traverseLast +~ 1 $ [1,2,3] -- [1,2,4] -- -- @'traverseLast' :: 'Applicative' f => (a -> f a) -> [a] -> f [a]@ traverseLast :: SimpleIndexedTraversal Int [a] a traverseLast = index $ \f xs0 -> let go [a] n = return <$> f n a go (a:as) n = (a:) <$> (go as $! n + 1) go [] _ = pure [] in go xs0 (0::Int) where {-# INLINE traverseLast #-} -- | A traversal of all but the last element of a list -- -- The position of each element is available as the index. -- -- >>> traverseInit +~ 1 $ [1,2,3] -- [2,3,3] -- -- @'traverseInit' :: 'Applicative' f => (a -> f a) -> [a] -> f [a]@ traverseInit :: SimpleIndexedTraversal Int [a] a traverseInit = index $ \f aas -> case aas of [] -> pure [] as -> (++ [Prelude.last as]) <$> itraverse f (Prelude.init as) {-# INLINE traverseInit #-}