safe-0.3.9/0000755000000000000000000000000012523463433010634 5ustar0000000000000000safe-0.3.9/Setup.hs0000644000000000000000000000005512523463433012270 0ustar0000000000000000import Distribution.Simple main = defaultMainsafe-0.3.9/Safe.hs0000644000000000000000000002241112523463433012046 0ustar0000000000000000{- | A module wrapping @Prelude@/@Data.List@ functions that can throw exceptions, such as @head@ and @!!@. Each unsafe function has up to four variants, e.g. with @tail@: * @'tail' :: [a] -> [a]@, raises an error on @tail []@. * @'tailMay' :: [a] -> /Maybe/ [a]@, turns errors into @Nothing@. * @'tailDef' :: /[a]/ -> [a] -> [a]@, takes a default to return on errors. * @'tailNote' :: /String/ -> [a] -> [a]@, takes an extra argument which supplements the error message. * @'tailSafe' :: [a] -> [a]@, returns some sensible default if possible, @[]@ in the case of @tail@. This module also introduces some new functions, documented at the top of the module. -} module Safe( -- * New functions abort, at, lookupJust, findJust, elemIndexJust, findIndexJust, -- * Safe wrappers tailMay, tailDef, tailNote, tailSafe, initMay, initDef, initNote, initSafe, headMay, headDef, headNote, lastMay, lastDef, lastNote, minimumMay, minimumDef, minimumNote, maximumMay, maximumDef, maximumNote, minimumByMay, minimumByDef, minimumByNote, maximumByMay, maximumByDef, maximumByNote, foldr1May, foldr1Def, foldr1Note, foldl1May, foldl1Def, foldl1Note, foldl1May', foldl1Def', foldl1Note', scanl1May, scanl1Def, scanl1Note, scanr1May, scanr1Def, scanr1Note, fromJustDef, fromJustNote, assertNote, atMay, atDef, atNote, readMay, readDef, readNote, lookupJustDef, lookupJustNote, findJustDef, findJustNote, elemIndexJustDef, elemIndexJustNote, findIndexJustDef, findIndexJustNote, toEnumMay, toEnumDef, toEnumNote, toEnumSafe ) where import Safe.Util import Data.List import Data.Maybe --------------------------------------------------------------------- -- UTILITIES fromNote = fromNoteModule "Safe" fromNoteEither = fromNoteEitherModule "Safe" --------------------------------------------------------------------- -- IMPLEMENTATIONS -- | Synonym for 'error'. Used for instances where the program -- has decided to exit because of invalid user input, or the user pressed -- quit etc. This function allows 'error' to be reserved for programmer errors. abort :: String -> a abort = error at_ :: [a] -> Int -> Either String a at_ xs o | o < 0 = Left $ "index must not be negative, index=" ++ show o | otherwise = f o xs where f 0 (x:xs) = Right x f i (x:xs) = f (i-1) xs f i [] = Left $ "index too large, index=" ++ show o ++ ", length=" ++ show (o-i) read_ :: Read a => String -> Either String a read_ s = case [x | (x,t) <- reads s, ("","") <- lex t] of [x] -> Right x [] -> Left $ "no parse on " ++ prefix _ -> Left $ "ambiguous parse on " ++ prefix where maxLength = 15 prefix = '\"' : a ++ if length s <= maxLength then (b ++ "\"") else "...\"" where (a,b) = splitAt (maxLength - 3) s --------------------------------------------------------------------- -- WRAPPERS -- | -- > tailMay [] = Nothing -- > tailMay [1,3,4] = Just [3,4] tailMay :: [a] -> Maybe [a] tailMay = liftMay null tail -- | -- > tailDef [12] [] = [12] -- > tailDef [12] [1,3,4] = [3,4] tailDef :: [a] -> [a] -> [a] tailDef def = fromMaybe def . tailMay -- | -- > tailNote "help me" [] = error "Safe.tailNote [], help me" -- > tailNote "help me" [1,3,4] = [3,4] tailNote :: String -> [a] -> [a] tailNote note = fromNote note "tailNote []" . tailMay -- | -- > tailSafe [] = [] -- > tailSafe [1,3,4] = [3,4] tailSafe :: [a] -> [a] tailSafe = tailDef [] initMay :: [a] -> Maybe [a] initMay = liftMay null init initDef :: [a] -> [a] -> [a] initDef def = fromMaybe def . initMay initNote :: String -> [a] -> [a] initNote note = fromNote note "initNote []" . initMay initSafe :: [a] -> [a] initSafe = initDef [] headMay, lastMay :: [a] -> Maybe a headMay = liftMay null head lastMay = liftMay null last headDef, lastDef :: a -> [a] -> a headDef def = fromMaybe def . headMay lastDef def = fromMaybe def . lastMay headNote, lastNote :: String -> [a] -> a headNote note = fromNote note "headNote []" . headMay lastNote note = fromNote note "lastNote []" . lastMay minimumMay, maximumMay :: Ord a => [a] -> Maybe a minimumMay = liftMay null minimum maximumMay = liftMay null maximum minimumDef, maximumDef :: Ord a => a -> [a] -> a minimumDef def = fromMaybe def . minimumMay maximumDef def = fromMaybe def . maximumMay minimumNote, maximumNote :: Ord a => String -> [a] -> a minimumNote note = fromNote note "minumumNote []" . minimumMay maximumNote note = fromNote note "maximumNote []" . maximumMay minimumByMay, maximumByMay :: (a -> a -> Ordering) -> [a] -> Maybe a minimumByMay = liftMay null . minimumBy maximumByMay = liftMay null . maximumBy minimumByDef, maximumByDef :: a -> (a -> a -> Ordering) -> [a] -> a minimumByDef def = fromMaybe def .^ minimumByMay maximumByDef def = fromMaybe def .^ maximumByMay minimumByNote, maximumByNote :: String -> (a -> a -> Ordering) -> [a] -> a minimumByNote note = fromNote note "minumumByNote []" .^ minimumByMay maximumByNote note = fromNote note "maximumByNote []" .^ maximumByMay foldr1May, foldl1May, foldl1May' :: (a -> a -> a) -> [a] -> Maybe a foldr1May = liftMay null . foldr1 foldl1May = liftMay null . foldl1 foldl1May' = liftMay null . foldl1' foldr1Def, foldl1Def, foldl1Def' :: a -> (a -> a -> a) -> [a] -> a foldr1Def def = fromMaybe def .^ foldr1May foldl1Def def = fromMaybe def .^ foldl1May foldl1Def' def = fromMaybe def .^ foldl1May' foldr1Note, foldl1Note, foldl1Note' :: String -> (a -> a -> a) -> [a] -> a foldr1Note note = fromNote note "foldr1Note []" .^ foldr1May foldl1Note note = fromNote note "foldl1Note []" .^ foldl1May foldl1Note' note = fromNote note "foldl1Note []" .^ foldl1May' scanr1May, scanl1May :: (a -> a -> a) -> [a] -> Maybe [a] scanr1May = liftMay null . scanr1 scanl1May = liftMay null . scanl1 scanr1Def, scanl1Def :: [a] -> (a -> a -> a) -> [a] -> [a] scanr1Def def = fromMaybe def .^ scanr1May scanl1Def def = fromMaybe def .^ scanl1May scanr1Note, scanl1Note :: String -> (a -> a -> a) -> [a] -> [a] scanr1Note note = fromNote note "scanr1Note []" .^ scanr1May scanl1Note note = fromNote note "scanl1Note []" .^ scanl1May -- | An alternative name for 'fromMaybe', to fit the naming scheme of this package. -- Generally using 'fromMaybe' directly would be considered better style. fromJustDef :: a -> Maybe a -> a fromJustDef = fromMaybe fromJustNote :: String -> Maybe a -> a fromJustNote note = fromNote note "fromJustNote Nothing" assertNote :: String -> Bool -> a -> a assertNote note True val = val assertNote note False val = fromNote note "assertNote False" Nothing -- | Synonym for '!!', but includes more information in the error message. at :: [a] -> Int -> a at = fromNoteEither "" "at" .^ at_ atMay :: [a] -> Int -> Maybe a atMay = eitherToMaybe .^ at_ atDef :: a -> [a] -> Int -> a atDef def = fromMaybe def .^ atMay atNote :: String -> [a] -> Int -> a atNote note = fromNoteEither note "atNote" .^ at_ readMay :: Read a => String -> Maybe a readMay = eitherToMaybe . read_ readDef :: Read a => a -> String -> a readDef def = fromMaybe def . readMay readNote :: Read a => String -> String -> a readNote note = fromNoteEither note "readNote" . read_ -- | -- > lookupJust key = fromJust . lookup key lookupJust :: Eq a => a -> [(a,b)] -> b lookupJust = fromNote "" "lookupJust, no matching value" .^ lookup lookupJustDef :: Eq a => b -> a -> [(a,b)] -> b lookupJustDef def = fromMaybe def .^ lookup lookupJustNote :: Eq a => String -> a -> [(a,b)] -> b lookupJustNote note = fromNote note "lookupJustNote, no matching value" .^ lookup -- | -- > findJust op = fromJust . find op findJust :: (a -> Bool) -> [a] -> a findJust = fromNote "" "findJust, no matching value" .^ find findJustDef :: a -> (a -> Bool) -> [a] -> a findJustDef def = fromMaybe def .^ find findJustNote :: String -> (a -> Bool) -> [a] -> a findJustNote note = fromNote note "findJustNote, no matching value" .^ find -- | -- > elemIndexJust op = fromJust . elemIndex op elemIndexJust :: Eq a => a -> [a] -> Int elemIndexJust = fromNote "" "elemIndexJust, no matching value" .^ elemIndex elemIndexJustDef :: Eq a => Int -> a -> [a] -> Int elemIndexJustDef def = fromMaybe def .^ elemIndex elemIndexJustNote :: Eq a => String -> a -> [a] -> Int elemIndexJustNote note = fromNote note "elemIndexJustNote, no matching value" .^ elemIndex -- | -- > findIndexJust op = fromJust . findIndex op findIndexJust :: (a -> Bool) -> [a] -> Int findIndexJust = fromNote "" "findIndexJust, no matching value" .^ findIndex findIndexJustDef :: Int -> (a -> Bool) -> [a] -> Int findIndexJustDef def = fromMaybe def .^ findIndex findIndexJustNote :: String -> (a -> Bool) -> [a] -> Int findIndexJustNote note = fromNote note "findIndexJustNote, no matching value" .^ findIndex -- From http://stackoverflow.com/questions/2743858/safe-and-polymorphic-toenum -- answer by C. A. McCann toEnumMay :: (Enum a, Bounded a) => Int -> Maybe a toEnumMay i = let r = toEnum i max = maxBound `asTypeOf` r min = minBound `asTypeOf` r in if i >= fromEnum min && i <= fromEnum max then Just r else Nothing toEnumDef :: (Enum a, Bounded a) => a -> Int -> a toEnumDef def = fromMaybe def . toEnumMay toEnumNote :: (Enum a, Bounded a) => String -> Int -> a toEnumNote note = fromNote note "toEnumNote, out of range" . toEnumMay toEnumSafe :: (Enum a, Bounded a) => Int -> a toEnumSafe = toEnumDef minBound safe-0.3.9/safe.cabal0000644000000000000000000000357012523463433012543 0ustar0000000000000000cabal-version: >= 1.6 build-type: Simple name: safe version: 0.3.9 license: BSD3 license-file: LICENSE category: Unclassified author: Neil Mitchell maintainer: Neil Mitchell copyright: Neil Mitchell 2007-2015 homepage: https://github.com/ndmitchell/safe#readme synopsis: Library of safe (exception free) functions bug-reports: https://github.com/ndmitchell/safe/issues tested-with: GHC==7.10.1, GHC==7.8.4, GHC==7.6.3, GHC==7.4.2, GHC==7.2.2 description: A library wrapping @Prelude@/@Data.List@ functions that can throw exceptions, such as @head@ and @!!@. Each unsafe function has up to four variants, e.g. with @tail@: . * @tail :: [a] -> [a]@, raises an error on @tail []@. . * @tailMay :: [a] -> /Maybe/ [a]@, turns errors into @Nothing@. . * @tailDef :: /[a]/ -> [a] -> [a]@, takes a default to return on errors. . * @tailNote :: /String/ -> [a] -> [a]@, takes an extra argument which supplements the error message. . * @tailSafe :: [a] -> [a]@, returns some sensible default if possible, @[]@ in the case of @tail@. . This package is divided into three modules: . * "Safe" contains safe variants of @Prelude@ and @Data.List@ functions. . * "Safe.Foldable" contains safe variants of @Foldable@ functions. . * "Safe.Exact" creates crashing versions of functions like @zip@ (errors if the lists are not equal) and @take@ (errors if there are not enough elements), then wraps them to provide safe variants. extra-source-files: CHANGES.txt README.md source-repository head type: git location: https://github.com/ndmitchell/safe.git library build-depends: base < 5 exposed-modules: Safe Safe.Exact Safe.Foldable other-modules: Safe.Util safe-0.3.9/README.md0000644000000000000000000000232212523463433012112 0ustar0000000000000000# Safe [![Hackage version](https://img.shields.io/hackage/v/safe.svg?style=flat)](https://hackage.haskell.org/package/safe) [![Build Status](https://img.shields.io/travis/ndmitchell/safe.svg?style=flat)](https://travis-ci.org/ndmitchell/safe) A library wrapping `Prelude`/`Data.List` functions that can throw exceptions, such as `head` and `!!`. Each unsafe function has up to four variants, e.g. with `tail`: * tail :: [a] -> [a], raises an error on `tail []`. * tailMay :: [a] -> Maybe [a], turns errors into `Nothing`. * tailDef :: [a] -> [a] -> [a], takes a default to return on errors. * tailNote :: String -> [a] -> [a], takes an extra argument which supplements the error message. * tailSafe :: [a] -> [a], returns some sensible default if possible, `[]` in the case of `tail`. This package is divided into three modules: * `Safe` contains safe variants of `Prelude` and `Data.List` functions. * `Safe.Foldable` contains safe variants of `Foldable` functions. * `Safe.Exact` creates crashing versions of functions like `zip` (errors if the lists are not equal) and `take` (errors if there are not enough elements), then wraps them to provide safe variants. safe-0.3.9/LICENSE0000644000000000000000000000276412523463433011652 0ustar0000000000000000Copyright Neil Mitchell 2007-2015. 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 Neil Mitchell 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. safe-0.3.9/CHANGES.txt0000644000000000000000000000131712523463433012447 0ustar0000000000000000Changelog for Safe 0.3.9 #9, add Safe toEnum 0.3.8 #8, remove unnecessary Ord constraints from Foldable functions 0.3.7 Add Def variants of the Exact functions 0.3.6 #6, remove unnecessary Ord constraints from maximumBy/minimumBy 0.3.5 Add Safe elemIndexJust/findIndexJust functions Add Safe scan functions Add Safe minimumBy/maximumBy functions Add a module of Exact functions Add Foldable minimum functions Clean up the Foldable module, deprecate the Safe variants 0.3.4 #1, improve the string clipping in readNote 0.3.3 #494, add foldl1' wrappings 0.3.2 Add a Safe.Foldable module 0.3.1 Add findJust, safe wrapping of fromJust/find 0.3 Start of changelog safe-0.3.9/Safe/0000755000000000000000000000000012523463433011512 5ustar0000000000000000safe-0.3.9/Safe/Util.hs0000644000000000000000000000157512523463433012773 0ustar0000000000000000 -- | Internal utilities. module Safe.Util where import Data.Maybe (.^) :: (b -> c) -> (a1 -> a2 -> b) -> a1 -> a2 -> c (.^) f g x1 x2 = f (g x1 x2) (.^^) :: (b -> c) -> (a1 -> a2 -> a3 -> b) -> a1 -> a2 -> a3 -> c (.^^) f g x1 x2 x3 = f (g x1 x2 x3) liftMay :: (a -> Bool) -> (a -> b) -> (a -> Maybe b) liftMay test func val = if test val then Nothing else Just $ func val fromNoteModule :: String -> String -> String -> Maybe a -> a fromNoteModule modu note func = fromMaybe (error msg) where msg = modu ++ "." ++ func ++ (if null note then "" else ", " ++ note) fromNoteEitherModule :: String -> String -> String -> Either String a -> a fromNoteEitherModule modu note func = either (error . msg) id where msg ex = modu ++ "." ++ func ++ " " ++ ex ++ (if null note then "" else ", " ++ note) eitherToMaybe :: Either a b -> Maybe b eitherToMaybe = either (const Nothing) Just safe-0.3.9/Safe/Foldable.hs0000644000000000000000000000671512523463433013567 0ustar0000000000000000{-# OPTIONS_GHC -fno-warn-unused-imports #-} -- Monoid required < 7.9 {- | 'Foldable' functions, with wrappers like the "Safe" module. -} module Safe.Foldable( -- * New functions findJust, -- * Safe wrappers foldl1May, foldl1Def, foldl1Note, foldr1May, foldr1Def, foldr1Note, findJustDef, findJustNote, minimumMay, minimumDef, minimumNote, maximumMay, maximumDef, maximumNote, minimumByMay, minimumByDef, minimumByNote, maximumByMay, maximumByDef, maximumByNote, -- * Deprecated foldl1Safe, foldr1Safe, findJustSafe ) where import Safe.Util import Data.Foldable as F import Data.Monoid import Data.Maybe --------------------------------------------------------------------- -- UTILITIES fromNote = fromNoteModule "Safe.Foldable" isNull :: Foldable t => t a -> Bool isNull = null . toList --------------------------------------------------------------------- -- WRAPPERS foldl1May, foldr1May :: Foldable t => (a -> a -> a) -> t a -> Maybe a foldl1May = liftMay isNull . F.foldl1 foldr1May = liftMay isNull . F.foldr1 foldl1Note, foldr1Note :: Foldable t => String -> (a -> a -> a) -> t a -> a foldl1Note note = fromNote note "foldl1Note on empty" .^ foldl1May foldr1Note note = fromNote note "foldr1Note on empty" .^ foldr1May foldl1Def, foldr1Def :: Foldable t => a -> (a -> a -> a) -> t a -> a foldl1Def def = fromMaybe def .^ foldl1May foldr1Def def = fromMaybe def .^ foldr1May minimumMay, maximumMay :: (Foldable t, Ord a) => t a -> Maybe a minimumMay = liftMay isNull F.minimum maximumMay = liftMay isNull F.maximum minimumDef, maximumDef :: (Foldable t, Ord a) => a -> t a -> a minimumDef def = fromMaybe def . minimumMay maximumDef def = fromMaybe def . maximumMay minimumNote, maximumNote :: (Foldable t, Ord a) => String -> t a -> a minimumNote note = fromNote note "minimumNote on empty" . minimumMay maximumNote note = fromNote note "maximumNote on empty" . maximumMay minimumByMay, maximumByMay :: (Foldable t) => (a -> a -> Ordering) -> t a -> Maybe a minimumByMay = liftMay isNull . F.minimumBy maximumByMay = liftMay isNull . F.maximumBy minimumByDef, maximumByDef :: (Foldable t) => a -> (a -> a -> Ordering) -> t a -> a minimumByDef def = fromMaybe def .^ minimumByMay maximumByDef def = fromMaybe def .^ maximumByMay minimumByNote, maximumByNote :: (Foldable t) => String -> (a -> a -> Ordering) -> t a -> a minimumByNote note = fromNote note "minimumByNote on empty" .^ minimumByMay maximumByNote note = fromNote note "maximumByNote on empty" .^ maximumByMay -- | -- > findJust op = fromJust . find op findJust :: Foldable t => (a -> Bool) -> t a -> a findJust = fromNote "" "findJust, no matching value" .^ F.find findJustDef :: Foldable t => a -> (a -> Bool) -> t a -> a findJustDef def = fromMaybe def .^ F.find findJustNote :: Foldable t => String -> (a -> Bool) -> t a -> a findJustNote note = fromNote note "findJustNote, no matching value" .^ F.find --------------------------------------------------------------------- -- DEPRECATED {-# DEPRECATED foldl1Safe "Use @foldl f mempty@ instead." #-} foldl1Safe :: (Monoid m, Foldable t) => (m -> m -> m) -> t m -> m foldl1Safe fun = F.foldl fun mempty {-# DEPRECATED foldr1Safe "Use @foldr f mempty@ instead." #-} foldr1Safe :: (Monoid m, Foldable t) => (m -> m -> m) -> t m -> m foldr1Safe fun = F.foldr fun mempty {-# DEPRECATED findJustSafe "Use @findJustDef mempty@ instead." #-} findJustSafe :: (Monoid m, Foldable t) => (m -> Bool) -> t m -> m findJustSafe = findJustDef mempty safe-0.3.9/Safe/Exact.hs0000644000000000000000000001262212523463433013115 0ustar0000000000000000{- | Provides functions that raise errors in corner cases instead of returning \"best effort\" results, then provides wrappers like the "Safe" module. For example: * @'takeExact' 3 [1,2]@ raises an error, in contrast to 'take' which would return just two elements. * @'takeExact' (-1) [1,2]@ raises an error, in contrast to 'take' which would return no elements. * @'zip' [1,2] [1]@ raises an error, in contrast to 'zip' which would only pair up the first element. Note that the @May@ variants of these functions are /strict/ in at least the bit of the prefix of the list required to spot errors. The standard and @Note@ versions are lazy, but throw errors later in the process - they do not check upfront. -} module Safe.Exact( -- * New functions takeExact, dropExact, splitAtExact, zipExact, zipWithExact, -- * Safe wrappers takeExactMay, takeExactNote, takeExactDef, dropExactMay, dropExactNote, dropExactDef, splitAtExactMay, splitAtExactNote, splitAtExactDef, zipExactMay, zipExactNote, zipExactDef, zipWithExactMay, zipWithExactNote, zipWithExactDef, ) where import Control.Arrow import Data.Maybe import Safe.Util --------------------------------------------------------------------- -- HELPERS addNote note fun msg = error $ "Safe.Exact." ++ fun ++ ", " ++ msg ++ (if null note then "" else ", " ++ note) --------------------------------------------------------------------- -- IMPLEMENTATIONS {-# INLINE splitAtExact_ #-} splitAtExact_ :: (String -> r) -> ([a] -> r) -> (a -> r -> r) -> Int -> [a] -> r splitAtExact_ err nil cons o xs | o < 0 = err $ "index must not be negative, index=" ++ show o | otherwise = f o xs where f 0 xs = nil xs f i (x:xs) = x `cons` f (i-1) xs f i [] = err $ "index too large, index=" ++ show o ++ ", length=" ++ show (o-i) {-# INLINE zipWithExact_ #-} zipWithExact_ :: (String -> r) -> r -> (a -> b -> r -> r) -> [a] -> [b] -> r zipWithExact_ err nil cons = f where f (x:xs) (y:ys) = cons x y $ f xs ys f [] [] = nil f [] _ = err "second list is longer than the first" f _ [] = err "first list is longer than the second" --------------------------------------------------------------------- -- TAKE/DROP/SPLIT -- | -- > takeExact n xs = -- > | n >= 0 && n <= length xs = take n xs -- > | otherwise = error "some message" takeExact :: Int -> [a] -> [a] takeExact = splitAtExact_ (addNote "" "takeExact") (const []) (:) -- | -- > dropExact n xs = -- > | n >= 0 && n <= length xs = drop n xs -- > | otherwise = error "some message" dropExact :: Int -> [a] -> [a] dropExact = splitAtExact_ (addNote "" "dropExact") id (flip const) -- | -- > splitAtExact n xs = -- > | n >= 0 && n <= length xs = splitAt n xs -- > | otherwise = error "some message" splitAtExact :: Int -> [a] -> ([a], [a]) splitAtExact = splitAtExact_ (addNote "" "splitAtExact") (\x -> ([], x)) (\a b -> first (a:) b) takeExactNote :: String -> Int -> [a] -> [a] takeExactNote note = splitAtExact_ (addNote note "takeExactNote") (const []) (:) takeExactMay :: Int -> [a] -> Maybe [a] takeExactMay = splitAtExact_ (const Nothing) (const $ Just []) (\a -> fmap (a:)) takeExactDef :: [a] -> Int -> [a] -> [a] takeExactDef def = fromMaybe def .^ takeExactMay dropExactNote :: String -> Int -> [a] -> [a] dropExactNote note = splitAtExact_ (addNote note "dropExactNote") id (flip const) dropExactMay :: Int -> [a] -> Maybe [a] dropExactMay = splitAtExact_ (const Nothing) Just (flip const) dropExactDef :: [a] -> Int -> [a] -> [a] dropExactDef def = fromMaybe def .^ dropExactMay splitAtExactNote :: String -> Int -> [a] -> ([a], [a]) splitAtExactNote note = splitAtExact_ (addNote note "splitAtExactNote") (\x -> ([], x)) (\a b -> first (a:) b) splitAtExactMay :: Int -> [a] -> Maybe ([a], [a]) splitAtExactMay = splitAtExact_ (const Nothing) (\x -> Just ([], x)) (\a b -> fmap (first (a:)) b) splitAtExactDef :: ([a], [a]) -> Int -> [a] -> ([a], [a]) splitAtExactDef def = fromMaybe def .^ splitAtExactMay --------------------------------------------------------------------- -- ZIP -- | -- > zipExact xs ys = -- > | length xs == length ys = zip xs ys -- > | otherwise = error "some message" zipExact :: [a] -> [b] -> [(a,b)] zipExact = zipWithExact_ (addNote "" "zipExact") [] (\a b xs -> (a,b) : xs) -- | -- > zipWithExact f xs ys = -- > | length xs == length ys = zipWith f xs ys -- > | otherwise = error "some message" zipWithExact :: (a -> b -> c) -> [a] -> [b] -> [c] zipWithExact f = zipWithExact_ (addNote "" "zipWithExact") [] (\a b xs -> f a b : xs) zipExactNote :: String -> [a] -> [b] -> [(a,b)] zipExactNote note = zipWithExact_ (addNote note "zipExactNote") [] (\a b xs -> (a,b) : xs) zipExactMay :: [a] -> [b] -> Maybe [(a,b)] zipExactMay = zipWithExact_ (const Nothing) (Just []) (\a b xs -> fmap ((a,b) :) xs) zipExactDef :: [(a,b)] -> [a] -> [b] -> [(a,b)] zipExactDef def = fromMaybe def .^ zipExactMay zipWithExactNote :: String -> (a -> b -> c) -> [a] -> [b] -> [c] zipWithExactNote note f = zipWithExact_ (addNote note "zipWithExactNote") [] (\a b xs -> f a b : xs) zipWithExactMay :: (a -> b -> c) -> [a] -> [b] -> Maybe [c] zipWithExactMay f = zipWithExact_ (const Nothing) (Just []) (\a b xs -> fmap (f a b :) xs) zipWithExactDef :: [c] -> (a -> b -> c) -> [a] -> [b] -> [c] zipWithExactDef def = fromMaybe def .^^ zipWithExactMay