dev: lib: Hledger.Utils cleanup

This commit is contained in:
Simon Michael 2022-11-04 19:12:19 -10:00
parent 79047ccc43
commit b079bbdb4e
3 changed files with 72 additions and 75 deletions

View File

@ -5,7 +5,10 @@ These are the bottom of hledger's module graph.
module Hledger.Utils ( module Hledger.Utils (
-- * Currying -- * Functions
applyN,
mapM',
sequence',
curry2, curry2,
uncurry2, uncurry2,
curry3, curry3,
@ -14,7 +17,11 @@ module Hledger.Utils (
uncurry4, uncurry4,
-- * Lists -- * Lists
maximum',
maximumStrict,
minimumStrict,
splitAtElement, splitAtElement,
sumStrict,
-- * Trees -- * Trees
treeLeaves, treeLeaves,
@ -40,21 +47,9 @@ module Hledger.Utils (
sixth6, sixth6,
-- * Misc -- * Misc
applyN,
mapM',
maximum',
maximumStrict,
minimumStrict,
numDigitsInt, numDigitsInt,
sequence',
sumStrict,
makeHledgerClassyLenses, makeHledgerClassyLenses,
-- * Tests
tests_Utils,
module Hledger.Utils.Test,
-- * Other -- * Other
module Hledger.Utils.Debug, module Hledger.Utils.Debug,
module Hledger.Utils.Parse, module Hledger.Utils.Parse,
@ -63,6 +58,10 @@ module Hledger.Utils (
module Hledger.Utils.String, module Hledger.Utils.String,
module Hledger.Utils.Text, module Hledger.Utils.Text,
-- * Tests
tests_Utils,
module Hledger.Utils.Test,
) )
where where
@ -83,7 +82,38 @@ import Hledger.Utils.Text
import Hledger.Utils.Test import Hledger.Utils.Test
-- Currying -- Functions
-- | Apply a function the specified number of times,
-- which should be > 0 (otherwise does nothing).
-- Possibly uses O(n) stack ?
applyN :: Int -> (a -> a) -> a -> a
applyN n f | n < 1 = id
| otherwise = (!! n) . iterate f
-- from protolude, compare
-- applyN :: Int -> (a -> a) -> a -> a
-- applyN n f = X.foldr (.) identity (X.replicate n f)
-- | Like mapM but uses sequence'.
{-# INLINABLE mapM' #-}
mapM' :: Monad f => (a -> f b) -> [a] -> f [b]
mapM' f = sequence' . map f
-- | This is a version of sequence based on difference lists. It is
-- slightly faster but we mostly use it because it uses the heap
-- instead of the stack. This has the advantage that Neil Mitchells
-- trick of limiting the stack size to discover space leaks doesnt
-- show this as a false positive.
{-# INLINABLE sequence' #-}
sequence' :: Monad f => [f a] -> f [a]
sequence' ms = do
h <- go id ms
return (h [])
where
go h [] = return h
go h (m:ms') = do
x <- m
go (h . (x :)) ms'
curry2 :: ((a, b) -> c) -> a -> b -> c curry2 :: ((a, b) -> c) -> a -> b -> c
curry2 f x y = f (x, y) curry2 f x y = f (x, y)
@ -105,6 +135,21 @@ uncurry4 f (w, x, y, z) = f w x y z
-- Lists -- Lists
-- | Total version of maximum, for integral types, giving 0 for an empty list.
maximum' :: Integral a => [a] -> a
maximum' [] = 0
maximum' xs = maximumStrict xs
-- | Strict version of maximum that doesnt leak space
{-# INLINABLE maximumStrict #-}
maximumStrict :: Ord a => [a] -> a
maximumStrict = foldl1' max
-- | Strict version of minimum that doesnt leak space
{-# INLINABLE minimumStrict #-}
minimumStrict :: Ord a => [a] -> a
minimumStrict = foldl1' min
splitAtElement :: Eq a => a -> [a] -> [[a]] splitAtElement :: Eq a => a -> [a] -> [[a]]
splitAtElement x l = splitAtElement x l =
case l of case l of
@ -115,6 +160,11 @@ splitAtElement x l =
split es = let (first,rest) = break (x==) es split es = let (first,rest) = break (x==) es
in first : splitAtElement x rest in first : splitAtElement x rest
-- | Strict version of sum that doesnt leak space
{-# INLINABLE sumStrict #-}
sumStrict :: Num a => [a] -> a
sumStrict = foldl' (+) 0
-- Trees -- Trees
-- | Get the leaves of this tree as a list. -- | Get the leaves of this tree as a list.
@ -149,57 +199,6 @@ sixth6 (_,_,_,_,_,x) = x
-- Misc -- Misc
-- | Apply a function the specified number of times,
-- which should be > 0 (otherwise does nothing).
-- Possibly uses O(n) stack ?
applyN :: Int -> (a -> a) -> a -> a
applyN n f | n < 1 = id
| otherwise = (!! n) . iterate f
-- from protolude, compare
-- applyN :: Int -> (a -> a) -> a -> a
-- applyN n f = X.foldr (.) identity (X.replicate n f)
-- | Total version of maximum, for integral types, giving 0 for an empty list.
maximum' :: Integral a => [a] -> a
maximum' [] = 0
maximum' xs = maximumStrict xs
-- | Strict version of sum that doesnt leak space
{-# INLINABLE sumStrict #-}
sumStrict :: Num a => [a] -> a
sumStrict = foldl' (+) 0
-- | Strict version of maximum that doesnt leak space
{-# INLINABLE maximumStrict #-}
maximumStrict :: Ord a => [a] -> a
maximumStrict = foldl1' max
-- | Strict version of minimum that doesnt leak space
{-# INLINABLE minimumStrict #-}
minimumStrict :: Ord a => [a] -> a
minimumStrict = foldl1' min
-- | This is a version of sequence based on difference lists. It is
-- slightly faster but we mostly use it because it uses the heap
-- instead of the stack. This has the advantage that Neil Mitchells
-- trick of limiting the stack size to discover space leaks doesnt
-- show this as a false positive.
{-# INLINABLE sequence' #-}
sequence' :: Monad f => [f a] -> f [a]
sequence' ms = do
h <- go id ms
return (h [])
where
go h [] = return h
go h (m:ms') = do
x <- m
go (h . (x :)) ms'
-- | Like mapM but uses sequence'.
{-# INLINABLE mapM' #-}
mapM' :: Monad f => (a -> f b) -> [a] -> f [b]
mapM' f = sequence' . map f
-- | Find the number of digits of an 'Int'. -- | Find the number of digits of an 'Int'.
{-# INLINE numDigitsInt #-} {-# INLINE numDigitsInt #-}
numDigitsInt :: Integral a => Int -> a numDigitsInt :: Integral a => Int -> a

View File

@ -23,8 +23,7 @@ where PROGNAME is the executable name returned by @getProgName@.
If using the logging feature you should ensure a stable program name If using the logging feature you should ensure a stable program name
by setting it explicitly with @withProgName@ at the start of your program by setting it explicitly with @withProgName@ at the start of your program
(since otherwise it will change to "<interactive>" when you are testing in GHCI). (since otherwise it will change to "<interactive>" when you are testing in GHCI).
Eg: Eg: @main = withProgName "MYPROG" $ do ...@.
@main = withProgName "MYPROG" $ do ...@.
The "traceOrLog" and "dbg" functions normally print to stderr, but if the program name The "traceOrLog" and "dbg" functions normally print to stderr, but if the program name
has been set to "MYPROG,logging" (ie, with a ",logging" suffix), they will log to has been set to "MYPROG,logging" (ie, with a ",logging" suffix), they will log to
@ -41,6 +40,7 @@ If you are working in GHCI, changing the debug level requires editing and reload
In hledger, debug levels are used as follows: In hledger, debug levels are used as follows:
@
Debug level: What to show: Debug level: What to show:
------------ --------------------------------------------------------- ------------ ---------------------------------------------------------
0 normal command output only (no warnings, eg) 0 normal command output only (no warnings, eg)
@ -53,6 +53,7 @@ Debug level: What to show:
7 input file reading, more detail 7 input file reading, more detail
8 command line parsing 8 command line parsing
9 any other rarely needed / more in-depth info 9 any other rarely needed / more in-depth info
@
-} -}
@ -164,13 +165,10 @@ progName =
then reverse $ drop 8 $ reverse modifiedProgName then reverse $ drop 8 $ reverse modifiedProgName
else modifiedProgName else modifiedProgName
-- | Global debug output level. This is the requested verbosity of -- | The programs debug output verbosity. The default is 0 meaning no debug output.
-- debug output printed to stderr. The default is 0 meaning no debug output.
-- The @--debug@ command line flag sets it to 1, or @--debug=N@ sets it to -- The @--debug@ command line flag sets it to 1, or @--debug=N@ sets it to
-- a higher value (note: not @--debug N@ for some reason). This uses -- a higher value (the = is required). Uses unsafePerformIO.
-- unsafePerformIO and can be accessed from anywhere and before normal -- When running in GHCI, changing this requires reloading this module.
-- command-line processing. When running with :main in GHCI, you must
-- touch and reload this module to see the effect of a new --debug option.
debugLevel :: Int debugLevel :: Int
debugLevel = case dropWhile (/="--debug") progArgs of debugLevel = case dropWhile (/="--debug") progArgs of
["--debug"] -> 1 ["--debug"] -> 1

View File

@ -1,6 +1,6 @@
{- | {- |
Helpers for pretty-formatting haskell values, pretty-printing to console, Helpers for pretty-printing haskell values, reading command line arguments,
deciding if ANSI colour should be used, and detecting an -o/--output-file option. working with ANSI colours, files, and time.
Uses unsafePerformIO. Uses unsafePerformIO.
Limitations: Limitations: