Useful (empty) → 0.0.1
raw patch · 8 files changed
+526/−0 lines, 8 filesdep +basedep +containersdep +randomsetup-changed
Dependencies added: base, containers, random
Files
- Setup.hs +2/−0
- Useful.cabal +13/−0
- Useful.hs +24/−0
- Useful/Dictionary.hs +93/−0
- Useful/General.hs +98/−0
- Useful/IO.hs +86/−0
- Useful/List.hs +168/−0
- Useful/String.hs +42/−0
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple +main = defaultMain
+ Useful.cabal view
@@ -0,0 +1,13 @@+Name: Useful +Version: 0.0.1 +Cabal-Version: >= 1.2 +License: BSD3 +Author: Daniel Holden +Maintainer: contact@theorangeduck.com +Synopsis: Some useful functions and shorthands. +Build-Type: Simple +Description: A library of some useful functions and some other short-hand or alias functions which I commonly use to make coding quicker and easier. This also includes a lightweight implementation of a dictionary using Data.Map. + +Library + Build-Depends: base >= 4 && < 5, random, containers + Exposed-Modules: Useful, Useful.General, Useful.Dictionary, Useful.List, Useful.String, Useful.IO
+ Useful.hs view
@@ -0,0 +1,24 @@+{- | + +These are a selection of useful haskell functions which I've written. + +It is split into 5 sections so as to allow you to import just one if you think the whole lot will clutter up the namepsace. + + * "Useful.General" - General shorthands and the most commonly used. + + * "Useful.Dictionary" - A lightweight dictionary implementation using Data.Map + + * "Useful.List" - Some general purpose list functions which are missing from Data.List as well as some other shorthands/aliases + + * "Useful.String" - A few string only functions which don't make sense over just lists + + * "Useful.IO" - Some shorthand and general purpose IO functions + +-} +module Useful(module Useful.General, module Useful.Dictionary, module Useful.List, module Useful.String, module Useful.IO) where + +import Useful.General +import Useful.Dictionary +import Useful.List +import Useful.String +import Useful.IO
+ Useful/Dictionary.hs view
@@ -0,0 +1,93 @@+-- | A lightweight Dictionary implementation based on Data.Map, part of the "Useful" module. +-- +-- So I kinda like dictionaries, but the functions and syntax by default are hardly as elegant as something like python. +-- This isn't a complete solution and nor is it optimal but it's pretty lightweight and pretty and stuff. You get it. +-- It's based off Data.Map so uses a binary tree and therefore the keys have to have some ordering defined over them. +module Useful.Dictionary where + +import qualified Data.Map + + +-- * Dictionary creation + +-- | Alias of Data.Map.fromList, takes a list of key value tuples and creates a dictionary out of them. +-- +-- > dict [("hello",1),("there",2)] +-- > fromList [("hello",1),("there",2)] +-- > dict [] +-- > fromList [] +dict :: (Ord k) => [(k, a)] -> Data.Map.Map k a +dict l = Data.Map.fromList l + +-- | Returns a List of key-value pairs +dictToList :: Data.Map.Map k a -> [(k, a)] +dictToList d = Data.Map.toList d + + +-- * Dictionary operations + +-- | Returns Maybe v from key k +(#!) :: (Ord k) => k -> Data.Map.Map k a -> Maybe a +(#!) d k = Data.Map.lookup d k + +-- | Returns v from key k or error. +(#!!) :: (Ord k) => Data.Map.Map k a -> k -> a +(#!!) d k = (Data.Map.!) d k + +-- | adds key-value pair to a dictionary. If key is already in dict will update value. +(#+) :: (Ord k) => Data.Map.Map k a -> (k,a) -> Data.Map.Map k a +(#+) d (k,v) = Data.Map.insert k v d + +-- | checks for a key in a dictionary. +(#?) :: (Ord k) => Data.Map.Map k a -> k -> Bool +(#?) d k = Data.Map.member k d + +-- | checks if a value is in a dictionary +(#*?) :: (Eq a, Ord k) => Data.Map.Map k a -> a -> Bool +(#*?) d v = (Data.Map.keys (Data.Map.filter (==v) d)) /= [] + +-- | Deletes a key-pair from a dictionary given a key +(#-) :: (Ord k) => Data.Map.Map k a -> k -> Data.Map.Map k a +(#-) d k = Data.Map.delete k d + +-- | Deletes ALL key-pairs from a dictionary given they match a value +(#*-) :: (Eq a, Ord k) => Data.Map.Map k a -> a -> Data.Map.Map k a +(#*-) d v = Data.Map.filter (/=v) d + +-- | Intersects two dictionaries +(#\\) :: (Ord k) => Data.Map.Map k a -> Data.Map.Map k b -> Data.Map.Map k a +(#\\) d1 d2 = (Data.Map.\\) d1 d2 + +-- | Unions two dictionaries +(#++) :: (Ord k) => Data.Map.Map k a -> Data.Map.Map k a -> Data.Map.Map k a +(#++) d1 d2 = Data.Map.union d1 d2 + +-- | Tests if d1 is a sub-dictionary of d2 +(#??) :: (Ord k, Eq a) => Data.Map.Map k a -> Data.Map.Map k a -> Bool +(#??) d1 d2 = Data.Map.isSubmapOf d1 d2 + +-- | Returns a the first occurance of a key from a value. Otherwise error. +(#?!) :: (Eq a, Ord k) => Data.Map.Map k a -> a -> k +(#?!) d v + |(Data.Map.filter (==v) d) == Data.Map.empty = error "value is not in dictionary" + |otherwise = head (Data.Map.keys (Data.Map.filter (==v) d)) + +-- | Returns the size of a dictionary +dictSize :: Data.Map.Map k a -> Int +dictSize d = Data.Map.size d + +-- | Data.Maps a function to all values in a dictionary +mapD :: (a -> b) -> Data.Map.Map k a -> Data.Map.Map k b +mapD func d = Data.Map.map func d + +-- | Data.Maps a function to all keys in a dictionary +mapDkeys :: (Ord k2) => (k1 -> k2) -> Data.Map.Map k1 a -> Data.Map.Map k2 a +mapDkeys func d = Data.Map.mapKeys func d + +-- | filter on a dincationy, you get the idea +filterD :: (Ord k) => (a -> Bool) -> Data.Map.Map k a -> Data.Map.Map k a +filterD func d = Data.Map.filter func d + +-- | filter for keys +filterDkeys :: (Ord k) => (k -> a -> Bool) -> Data.Map.Map k a -> Data.Map.Map k a +filterDkeys func d = Data.Map.filterWithKey func d
+ Useful/General.hs view
@@ -0,0 +1,98 @@+-- | General shorthands and other small operations. Part of the "Useful" module. +module Useful.General where + +import Data.List + +-- | Alias of as /= (not equal to) +(!=) :: Eq a => a -> a -> Bool +(!=) = (/=) + + +-- | Alias of mod +(%) = mod + + +-- | Works like python's \"in\" function. (Alias of elem). Simply checks if an item is in a list. +-- +-- > $ "Hello" ? ["Hello","there","people"] +-- > True +-- > $ "Bonjour" ? ["Hello","there","people"] +-- > False +(?) :: Eq a => a -> [a] -> Bool +(?) = elem + + +-- | Alias of as isInFixOf. Checks if list is a sublist of another list +-- +-- > $ "hello" ?? "Why hello there people" +-- > True +-- > $ [2,3] ?? [1,2,3,4] +-- > True +-- > $ "bonjour" ?? "why hello there people" +-- > False +(??) :: Eq a => [a] -> [a] -> Bool +(??) = isInfixOf + + +-- | Returns the index of the first occurance of an item if it is in a list. Otherwise gives an error. Also remember, starts counting from 0! +-- +-- NOTE: This is not like elemIndex! It does not return a Maybe Int it returns an error if the item is not in a list. Either use elemIndex or test using ? first. THIS FUNCTION IS NOT COMPLETE. +-- +-- > $ 'n' ?! "banana" +-- > 2 +-- > $ 'v' ?! "banana" +-- > *** Exception: Item not in list +(?!) :: Eq a => a -> [a] -> Int +(?!) x y = f x y 0 + where + f :: Eq a => a -> [a] -> Int -> Int + f x [] _ = error "Item not in list" + f x (y:ys) c + |x == y = c + |otherwise = f x ys (c+1) + +-- | Takes a list and a pair (x,y) and inserts the item y into the list at position x +-- +-- > $ ["hello","there","people"] !/ (0,"bonjour") +-- > ["bonjour","there","people"] +(!/) :: [a] -> (Int,a) -> [a] +(!/) xs (i,y) + |i >= len xs = error "index too large" + |otherwise = [if n == i then y else x | (x,n) <- zip xs [0..] ] + + +-- | Like !! but returns Maybe a +-- +-- > $ [1,2,3,4] ! 5 +-- > Nothing +-- > $ [1,2,3,4] ! 1 +-- > Just 2 +(!) :: [a] -> Int -> Maybe a +(!) xs i = plingHelper xs i 0 + +plingHelper [] _ _ = Nothing +plingHelper (x:xs) i n + |i == n = Just x + |otherwise = plingHelper xs i (n+1) + + +-- | alias of length +len :: [a] -> Int +len = length +-- | alias of length +count :: [a] -> Int +count = length + + +-- | Simple function that takes the unit list and returns the unit +-- +-- NOTE: Will return an error if not supplied with the unit list +-- +-- > $ the ["hello"] +-- > "hello" +-- > $ the ["hello","there"] +-- > "*** Exception: function 'the' called with a list other than the unit list. +the :: [a] -> a +the [x] = x +the _ = error "function 'the' called with a list other than the unit list." +
+ Useful/IO.hs view
@@ -0,0 +1,86 @@+-- | IO operations, part of the "Useful" module. +module Useful.IO where + +import Useful.General +import System.Random + + +-- | repeats an IO function n number of times. +replicateM :: (Monad m) => Int -> m a -> m [a] +replicateM n x = sequence (replicate n x) + +-- | Like replicateM but stores the returns +replicateM_ :: (Monad m) => Int -> m a -> m () +replicateM_ n x = sequence_ (replicate n x) + + + +-- | repeats an IO function for every member of a list, using the list item as an arguement +-- +-- > $ do foreach [1..3] print +-- > 1 +-- > 2 +-- > 3 +-- > $ do foreach "asjkdnsd" putChar +-- > asjkdnsd +foreach :: Monad m => [a] -> (a -> m b) -> m () +foreach = flip mapM_ + + +-- | repeats an IO function until a IO Bool is true +-- +-- NOTE: Be careful with this function! Better to use recursion. Testing against an item created in the loop will not work. +while :: (Monad m) => m Bool -> m a -> m () +while test action = do + val <- test + if val then do {action;while test action} + else return () + + +-- | like putStr or putChar but works on any type with \"show\" defined in a similar way to how print does. Can be thought of as \"print\" without the trailing linebreak. +-- +-- NOTE: This means it will print strings with quotes around them. To print strings without quotes use putStr or putStrLn +put :: Show a => a -> IO () +put x = putStr (show x) + +-- | Alias of put +write :: Show a => a -> IO () +write = put + + +-- | Alias of print +writeln :: (Show a) => a -> IO () +writeln = print + +-- | Alias of print +putln :: (Show a) => a -> IO () +putln = print + +-- maps an IO function in depth N to the given list. Also versions without _ for storing of the returns. +-- +-- Again there are also mapM_3, mapM_4 and mapM_5 defined (as well as versions without underscores) +-- +-- > $ mapM_2 write [[1,2,3,4,5],[1,2]] +-- > 1234512 +mapM_2 :: (Monad m) => (a -> m b) -> [[a]] -> m () +mapM_2 f x = mapM_ (mapM_ f) x +mapM_3 f x = mapM_ (mapM_ (mapM_ f)) x +mapM_4 f x = mapM_ (mapM_ (mapM_ (mapM_ f))) x +mapM_5 f x = mapM_ (mapM_ (mapM_ (mapM_ (mapM_ f)))) x + +mapM2 f x = mapM (mapM f) x +mapM3 f x = mapM (mapM (mapM f)) x +mapM4 f x = mapM (mapM (mapM (mapM f))) x +mapM5 f x = mapM (mapM (mapM (mapM (mapM f)))) x + + +-- | takes a list and returns a random element from that list +-- +-- > $ rand [1..5] +-- > 5 +-- > $ rand "hello there people" +-- > 'l' +rand :: [a] -> IO a +rand xs = do + i <- getStdRandom (randomR (0,(len xs)-1)) + return (xs !! i)
+ Useful/List.hs view
@@ -0,0 +1,168 @@+-- | Useful List operations, part of the "Useful" module. +module Useful.List where + +import Useful.General +import Data.List + + +-- | Takes a list item and splits a list around it, removing the item. +-- +-- > $ explodeI "Hello there people" ' ' +-- > ["Hello","there","people"] +explodeI :: Eq a => [a] -> a -> [[a]] +explodeI xs m = rmEmptyList (explode' xs m) + +-- explode' :: Eq a => [a] -> a -> [[a]] +explode' [] m = [] +explode' xs m = [takeWhile (!=m) xs] ++ explode' (tail' (dropWhile (!=m) xs)) m + where + tail' [] = [] + tail' (x:xs) = xs + +-- | Alias of explodeI +splitI :: Eq a => [a] -> a -> [[a]] +splitI = explodeI + + +-- | Take a list item and concatinates each element of it around another given item. +-- +-- > $implodeI "askjdnaskd" '!' +-- > "a!s!k!j!d!n!a!s!k!d" +implodeI :: Eq a => [a] -> a -> [a] +implodeI (x:xs) y + |xs == [] = [x] + |otherwise = (x : [y]) ++ (implodeI xs y) + +-- | alias of implodeI +joinI :: Eq a => [a] -> a -> [a] +joinI = implodeI + + +-- | Takes a two lists and explodes the first into a new list, around the second. Removing the second list where it occurs. +-- +-- THIS NEEDS FIXING +explode :: Eq a => [a] -> [a] -> [[a]] +explode x y = explode'' x y 0 0 + +-- explode'' :: Eq a => [a] -> [a] -> Int -> Int -> [[a]] +explode'' x y buff count + |x == y = [] + |x == [] = [] + |y == [] = [x] + |buff == len y = (takeBefore buff (fst splut)) : ( explode'' (snd splut) y 0 0) -- If the buffer is full (match found). Then split and remove match from fst, cons onto the explode'' of the second part. + |(len x < count) && ((x !! count) ? y) = explode'' x y (((x !! count) ?! y )+1) (count+1) -- is x !! count in y? If so then find at which position and explode'' with that +1 as the new buffer. + |otherwise = explode'' x y 0 (count+1) -- otherwise increment the counter. + where splut = (splitAt count x) + +-- | alias of explode +split :: Eq a => [a] -> [a] -> [[a]] +split = explode + + +-- | Takes a list of lists and an extra list and concatinates the list of lists with the second list inbetween. When used with the empty list mimics concat +-- +-- > $ implode ["helloasdad","asd hello","hello"] "!!" +-- > "helloasdad!!asd hello!!hello" +implode :: Eq a => [[a]] -> [a] -> [a] +implode x [] = concat x +implode (x:xs) y + |xs == [] = x + |otherwise = (x ++ y) ++ (implode xs y) + +-- | Alias of implode +join :: Eq a => [[a]] -> [a] -> [a] +join = implode + + +-- | takes n number of items from the front of a list +-- +-- > $ takeFor 5 "Hello there people" +-- > "Hello" +takeFor :: Eq a => Int -> [a] -> [a] +takeFor n x = takeFor' n x 0 + +takeFor' n (x:xs) c + |xs == [] = x: [] + |c == n = [] + |otherwise = x : takeFor' n xs (c+1) + + +-- | drops n number of items from the front of a list +-- +-- > $ dropFor 5 "Hello there people" +-- > " there people" +dropFor :: Eq a => Int -> [a] -> [a] +dropFor n x = dropFor' n x 0 + +dropFor' n (x:xs) c + |(xs == []) && (c <= n) = [] + |(xs == []) && (c > n) = (x:xs) + |c < n = [] ++ dropFor' n xs (c+1) + |otherwise = x : dropFor' n xs (c+1) + + +-- | takes a number of items from a list before it reaches the index n +-- +-- > $ takeBefore 5 "Hello there people" +-- > "Hello there p" +takeBefore :: Eq a => Int -> [a] -> [a] +takeBefore n x = takeFor' (len x - n) x 0 + + +-- | drops a number of items from a list before it reaches the index n +-- +-- > $ dropBefore 5 "Hello there people" +-- > "eople" +dropBefore :: Eq a => Int -> [a] -> [a] +dropBefore n x = dropFor' (len x - n) x 0 + + +-- | In a list of lists this removes any occurances of the empty list. Can also be used to remove occurances of the empty string. +rmEmptyList :: Eq a => [[a]] -> [[a]] +rmEmptyList [] = [] +rmEmptyList (x:xs) + |x == [] = rmEmptyList xs + |otherwise = x:(rmEmptyList xs) + + +-- | maps a function in depth N to the given list. map3, map4, map5 are also defined. +-- +-- > $ map2 (*2) [[1,2,3,4],[1,1,1,2]] +-- > [[2,4,6,8],[2,2,2,4]] +map2 :: (a -> b) -> [[a]] -> [[b]] +map2 f x = map (map f) x +map3 f x = map (map (map f)) x +map4 f x = map (map (map (map f))) x +map5 f x = map (map (map (map (map f)))) x + + +-- | returns a list of size n filled with items x +-- +-- > $ initList 0 5 +-- > [0,0,0,0,0] +initList :: a -> Int -> [a] +initList x 0 = [] +initList x n = x : (initList x (n-1)) + +-- | Replaces any occuranses of the second list, with the third list, in the first list. +-- +-- > $ replace "why hello hello there" "hello" "bonjour" +-- > "why bonjour bonjour there" +replace :: Eq a => [a] -> [a] -> [a] -> [a] +replace s [] x = s +replace [] _ _ = [] +replace s find repl + |take (length find) s == find = repl ++ (replace (drop (length find) s) find repl) + |otherwise = [head s] ++ (replace (tail s) find repl) + + +-- | Takes a list of items and returns a list with each element in it's own single list. +-- +-- > $ each "hello" +-- > ["h","e","l","l","o"] +each :: [a] -> [[a]] +each x = f x + where + f :: [a] -> [[a]] + f [] = [] + f (x:xs) = [x] : f xs
+ Useful/String.hs view
@@ -0,0 +1,42 @@+-- | String operations, part of the "Useful" module. +module Useful.String where + +import Useful.General + +-- | Strips whitespace from either side of a string. +-- +-- > $ strip " asdsadasds \r\n" \n +-- > "asdsadasds" +strip :: String -> String +strip = stripr . stripl + +-- | Strips whitespace from the right of a string +-- +-- > $ stripr " asdioamlksd \n\n" \n +-- > " asdioamlksd" +stripr :: String -> String +stripr [] = [] +stripr x + |(last x) ? stripset = stripr (init x) + |otherwise = x + +-- | Strips whitespace from the left of a string +-- +-- > $ stripl " \n\n askdjnasdnaskd" +-- > "askdjnasdnaskd" +stripl :: String -> String +stripl [] = [] +stripl (x:xs) + |x ? stripset = stripl xs + |otherwise = (x:xs) + +-- | Alias of 'strip' +chomp :: String -> String +chomp = stripr + +-- | List of whitespace characters: +-- +-- > [' ','\r','\n','\t'] +stripset :: [Char] +stripset = [' ','\r','\n','\t'] +