trade-journal-0.0.1: src/Journal/Utils.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}
module Journal.Utils where
import Control.Applicative
import Control.Arrow
import Control.Lens
import Control.Monad.Trans.Class
import Control.Monad.Trans.Reader
import Control.Monad.Trans.State
import Data.Coerce
import Data.Foldable
import Data.Text (Text)
import qualified Data.Text as T
import Data.Time
import Data.Time.Format.ISO8601
import Debug.Trace (traceM)
import Text.PrettyPrint as P
import Prelude hiding ((<>), Double, Float)
readonly :: Monad m => ReaderT s m a -> StateT s m a
readonly f = lift . runReaderT f =<< get
justify :: [a] -> [Maybe a]
justify [] = [Nothing]
justify (x : xs) = Just x : justify xs
unzipBoth :: [([a], [b])] -> ([a], [b])
unzipBoth = (concat *** concat) . unzip
distance :: UTCTime -> UTCTime -> Integer
distance x y = abs (utctDay x `diffDays` utctDay y)
renderM :: Applicative f => Doc -> f ()
renderM = traceM . render
percent :: (Num a, Num b, Coercible b a) => a -> Lens' b b
percent n f s = f part <&> \v -> v + (s - part)
where
part = s * coerce n
zipped :: Traversal' s a -> Traversal' s b -> Traversal' s (a, b)
zipped f g k s = case liftA2 (,) (s ^? f) (s ^? g) of
Nothing -> pure s
Just p -> k p <&> \(a, b) -> s & f .~ a & g .~ b
zipped3 ::
Traversal' s a ->
Traversal' s b ->
Traversal' s c ->
Traversal' s (a, b, c)
zipped3 f g h k s = case liftA3 (,,) (s ^? f) (s ^? g) (s ^? h) of
Nothing -> pure s
Just p -> k p <&> \(a, b, c) -> s & f .~ a & g .~ b & h .~ c
contractList :: (a -> a -> Maybe a) -> [a] -> [a]
contractList _ [] = []
contractList _ [x] = [x]
contractList f (x : y : xs) = case f x y of
Nothing -> x : contractList f (y : xs)
Just z -> contractList f (z : xs)
renderList :: (a -> Doc) -> [a] -> Doc
renderList _ [] = brackets P.empty
renderList f ts =
fst (foldl' go (P.empty, True) ts) <> space <> rbrack
where
go (_, True) x = (lbrack <> space <> f x, False)
go (acc, False) x = (acc $$ comma <> space <> f x, False)
class Render a where
rendered :: a -> Doc
instance Render a => Render [a] where
rendered = renderList rendered
instance Render a => Render (Maybe a) where
rendered Nothing = text "Nothing"
rendered (Just x) = text "Just" <> space <> rendered x
instance Render Text where
rendered = text . T.unpack
instance Render Day where
rendered = text . iso8601Show
instance Render UTCTime where
rendered = text . iso8601Show . utctDay
tshow :: Show a => a -> Doc
tshow = text . show
-- A Fold over the individual components of a Text split on a separator.
--
-- splitOn :: Text -> Fold String String
-- splitOn :: Text -> Traversal' String String
--
-- splitOn :: Text -> IndexedFold Int String String
-- splitOn :: Text -> IndexedTraversal' Int String String
--
-- Note: This function type-checks as a Traversal but it doesn't satisfy the
-- laws. It's only valid to use it when you don't insert any separator strings
-- while traversing, and if your original Text contains only isolated split
-- strings.
splitOn :: Applicative f => Text -> IndexedLensLike' Int f Text Text
splitOn s f = fmap (T.intercalate s) . go . T.splitOn s
where
go = conjoined traverse (indexing traverse) f