safe (empty) → 0.2
raw patch · 4 files changed
+307/−0 lines, 4 filesdep +basesetup-changed
Dependencies added: base
Files
- LICENSE +30/−0
- Safe.hs +254/−0
- Setup.hs +2/−0
- safe.cabal +21/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Neil Mitchell 2007-2008.+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.hs view
@@ -0,0 +1,254 @@++{- |+Module : Safe+Copyright : (c) Neil Mitchell 2007-2008+License : BSD3++Maintainer : http://www.cs.york.ac.uk/~ndm/+Stability : in-progress+Portability : portable++A library for safe functions, based on standard functions that may crash.+For more details see <http://www-users.cs.york.ac.uk/~ndm/safe/>++In general, each unsafe function has up to 4 forms.+Since 'tail' has all the possible forms, it is fully documented.+The others all follow the same pattern.+++* @Note@, takes an extra argument which supplements the error message, 'tailNote'++* @Def@, take an extra argument to give when a crash would otherwise happen, 'tailDef'++* @May@, wraps the result in a Maybe, 'tailMay'++* @Safe@, returns a default type if possible, 'tailSafe'++This library also introduces three brand new functions:++* 'at' - synonym for @(!!)@++* 'lookupJust' - defined as @lookupJust k = fromJust . lookup k@++* 'abort' - same as @error@, but different intended meaning++-}++module Safe(+ tailDef, tailMay, tailNote, tailSafe,+ initDef, initMay, initNote, initSafe,+ headDef, headMay, headNote,+ lastDef, lastMay, lastNote,+ minimumDef, minimumMay, minimumNote,+ maximumDef, maximumMay, maximumNote,+ foldr1Def, foldr1May, foldr1Note,+ foldl1Def, foldl1May, foldl1Note,+ fromJustDef, fromJustNote,+ assertNote,+ at, atDef, atMay, atNote,+ readDef, readMay, readNote,+ lookupJust, lookupJustDef, lookupJustNote,+ abort+ ) where+++import Data.Maybe++{-# PARTIAL tailNote, initNote, headNote, lastNote, minimumNote, maximumNote #-}+{-# PARTIAL foldr1Note, foldl1Note, fromJustNote, assertNote, at, atNote, readNote #-}+{-# PARTIAL lookupJustNote, lookupJust #-}+++liftDef :: (a -> b) -> (a -> Bool) -> b -> (a -> b)+liftDef func test def val = if test val then def else func val++liftMay :: (a -> b) -> (a -> Bool) -> (a -> Maybe b)+liftMay func test val = if test val then Nothing else Just $ func val++liftNote :: (a -> b) -> (a -> Bool) -> String -> String -> (a -> b)+liftNote func test caller note val =+ if test val+ then error $ "Pattern match failure, " ++ caller ++ ", " ++ note+ else func val++liftSafe :: (a -> a) -> (a -> Bool) -> (a -> a)+liftSafe func test val = if test val then val else func val+++-- |+-- > tailDef [12] [] = [12]+-- > tailDef [12] [1,3,4] = [3,4]+tailDef :: [a] -> [a] -> [a]+tailDef = liftDef tail null++-- |+-- > tailMay [] = Nothing+-- > tailMay [1,3,4] = Just [3,4]+tailMay :: [a] -> Maybe [a]+tailMay = liftMay tail null++-- |+-- > tail "help me" [] = error "Pattern match failure, tail [], help me"+-- > tail "help me" [1,3,4] = [3,4]+tailNote :: String -> [a] -> [a]+tailNote = liftNote tail null "tail []"++-- |+-- > tailSafe [] = []+-- > tailSafe [1,3,4] = [3,4]+tailSafe :: [a] -> [a]+tailSafe = liftSafe tail null+++initDef :: [a] -> [a] -> [a]+initDef = liftDef init null++initMay :: [a] -> Maybe [a]+initMay = liftMay init null++initNote :: String -> [a] -> [a]+initNote = liftNote init null "init []"++initSafe :: [a] -> [a]+initSafe = liftSafe init null++++headDef :: a -> [a] -> a+headDef = liftDef head null++headMay :: [a] -> Maybe a+headMay = liftMay head null++headNote :: String -> [a] -> a+headNote = liftNote head null "head []"+++lastDef :: a -> [a] -> a+lastDef = liftDef last null++lastMay :: [a] -> Maybe a+lastMay = liftMay last null++lastNote :: String -> [a] -> a+lastNote = liftNote last null "last []"++++minimumDef :: Ord a => a -> [a] -> a+minimumDef = liftDef minimum null++minimumMay :: Ord a => [a] -> Maybe a+minimumMay = liftMay minimum null++minimumNote :: Ord a => String -> [a] -> a+minimumNote = liftNote minimum null "minimum []"+++maximumDef :: Ord a => a -> [a] -> a+maximumDef = liftDef maximum null++maximumMay :: Ord a => [a] -> Maybe a+maximumMay = liftMay maximum null++maximumNote :: Ord a => String -> [a] -> a+maximumNote = liftNote maximum null "maximum []"++++foldr1Def :: a -> (a -> a -> a) -> [a] -> a+foldr1Def def f = liftDef (foldr1 f) null def++foldr1May :: (a -> a -> a) -> [a] -> Maybe a+foldr1May f = liftMay (foldr1 f) null++foldr1Note :: String -> (a -> a -> a) -> [a] -> a+foldr1Note note f = liftNote (foldr1 f) null "foldr1 []" note+++foldl1Def :: a -> (a -> a -> a) -> [a] -> a+foldl1Def def f = liftDef (foldl1 f) null def++foldl1May :: (a -> a -> a) -> [a] -> Maybe a+foldl1May f = liftMay (foldl1 f) null++foldl1Note :: String -> (a -> a -> a) -> [a] -> a+foldl1Note note f = liftNote (foldl1 f) null "foldl1 []" note+++-- | See fromMaybe+fromJustDef :: a -> Maybe a -> a+fromJustDef = liftDef fromJust isNothing++fromJustNote :: String -> Maybe a -> a+fromJustNote = liftNote fromJust isNothing "fromJust Nothing"++++assertNote :: String -> Bool -> a -> a+assertNote msg False val = error $ "assertion failed, " ++ msg+assertNote msg True val = val++++-- | Same as @(!!)@, but better error message+at :: [a] -> Int -> a+at = atNote "called by at"++atDef :: a -> [a] -> Int -> a+atDef def x n = fromMaybe def (atMay x n)++atMay :: [a] -> Int -> Maybe a+atMay xs n | n < 0 = Nothing+atMay [] _ = Nothing+atMay (x:_) 0 = Just x+atMay (_:xs) n = atMay xs (n-1)++atNote :: String -> [a] -> Int -> a+atNote msg _ n | n < 0 = error $ "Safe.at: negative index, " ++ msg+atNote msg xs n = f xs n+ where+ f [] i = error $ "Safe.at: index too large, index=" ++ show n ++ ", length=" ++ show (n-i) ++ ", " ++ msg+ f (x:_) 0 = x+ f (_:xs) i = f xs (i-1)++++readDef :: Read a => a -> String -> a+readDef def s = fromMaybe def (readMay s)++readMay :: Read a => String -> Maybe a+readMay s = case [x | (x,t) <- reads s, ("","") <- lex t] of+ [x] -> Just x+ _ -> Nothing++readNote :: Read a => String -> String -> a+readNote msg s = case [x | (x,t) <- reads s, ("","") <- lex t] of+ [x] -> x+ [] -> error $ "Prelude.read: no parse, " ++ msg ++ ", on " ++ prefix+ _ -> error $ "Prelude.read: ambiguous parse, " ++ msg ++ ", on " ++ prefix+ where+ prefix = '\"' : a ++ if null b then "\"" else "..."+ where (a,b) = splitAt 10 s+++-- |+-- > lookupJust key = fromJust . lookup key+lookupJust :: Eq a => a -> [(a,b)] -> b+lookupJust key = fromJustNote "lookupJust, item not found" . lookup key++lookupJustDef :: Eq a => b -> a -> [(a,b)] -> b+lookupJustDef def key lst = fromMaybe def (lookup key lst)++lookupJustNote :: Eq a => String -> a -> [(a,b)] -> b+lookupJustNote msg key lst = case lookup key lst of+ Nothing -> error $ "Safe.lookupJust: element not found, " ++ msg+ Just x -> x++++-- | Exactly the same as @error@. Use this for instances where the program+-- has decided to exit because of invalid user input, or the user pressed+-- quit etc. This allows @error@ to be reserved for genuine coding mistakes.+abort :: String -> a+abort = error
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ safe.cabal view
@@ -0,0 +1,21 @@+Name: safe+Build-Type: Simple+Version: 0.2+License: BSD3+License-File: LICENSE+Copyright: 2007-8, Neil Mitchell+Maintainer: ndmitchell@gmail.com+Author: Neil Mitchell+Homepage: http://www-users.cs.york.ac.uk/~ndm/safe/+Build-Depends: base+Category: Unclassified+Synopsis: Library for safe (pattern match free) functions+Description:+ Partial functions from the base library, such as @head@ and @!!@, modified+ to return more descriptive error messages, programmer defined error messages,+ @Maybe@ wrapped results and default values.+ + These functions can be used to reduce the number of unsafe pattern matches in+ your code.+Exposed-modules:+ Safe