1 {-# LANGUAGE DeriveDataTypeable #-}
2 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
3 {-# LANGUAGE NamedFieldPuns #-}
4 {-# LANGUAGE RecordWildCards #-}
5 {-# LANGUAGE TypeFamilies #-}
6 {-# OPTIONS_GHC -fno-warn-orphans #-}
7 module Hcompta.LCC.Journal where
9 -- import Data.NonNull (NonNull)
10 -- import Data.Text (Text)
11 -- import qualified Data.NonNull as NonNull
12 -- import qualified Data.Text as Text
13 import Control.DeepSeq (NFData(..))
14 import Data.Data (Data(..))
15 import Data.Eq (Eq(..))
16 import Data.Foldable (Foldable(..))
17 import Data.Function (($), (.))
18 import Data.Functor (Functor(..), (<$>))
19 import Data.Functor.Compose (Compose(..))
20 import Data.Map.Strict (Map)
21 -- import Data.Monoid (Monoid(..))
22 import Data.Ord (Ord(..))
23 -- import Data.String (IsString(..))
24 import Data.Traversable (Traversable(..))
25 import Data.TreeMap.Strict (TreeMap)
26 import Data.Typeable (Typeable)
28 import Text.Show (Show(..))
29 import qualified Data.MonoTraversable as MT
30 -- import qualified System.FilePath.Posix as FP
34 import Control.Monad (Monad(..), foldM)
35 import Data.List (reverse)
36 import Data.Maybe (Maybe(..))
37 import qualified Data.Monoid as Monoid
38 import Data.Semigroup (Semigroup(..))
41 import qualified Hcompta as H
42 -- import Hcompta.LCC.Account
43 -- import Hcompta.LCC.Amount
44 -- import Hcompta.LCC.Chart
46 import Hcompta.LCC.Posting
47 -- import Hcompta.LCC.Transaction
52 { journal_file :: !PathFile
53 , journal_last_read_time :: !Date
54 , journal_content :: !j
55 , journal_includes :: ![CanonFile]
56 } deriving (Data, Eq, Show, Typeable)
58 type instance MT.Element (Journal j) = j
59 instance Functor Journal where
60 fmap f j@Journal{journal_content{- DELME: , journal_includes-}} =
61 j{ journal_content = f journal_content
62 {- DELME: , journal_includes = fmap f <$> journal_includes-}
64 instance MT.MonoFunctor (Journal j)
65 instance Foldable Journal where
66 foldMap f Journal{journal_content{- DELME: , journal_includes-}} =
67 f journal_content {- DELME: `mappend`
68 (foldMap f `foldMap` journal_includes)-}
69 instance MT.MonoFoldable (Journal j)
70 instance Traversable Journal where
71 traverse f j = (\c -> j{journal_content=c}) <$> f (journal_content j)
72 instance NFData j => NFData (Journal j) where
74 rnf journal_file `seq`
75 rnf journal_last_read_time `seq`
76 rnf journal_content `seq`
79 journal :: j -> Journal j
83 , journal_last_read_time = H.epoch
85 , journal_includes = []
89 instance Semigroup j => Semigroup (Journal j) where
91 instance (Monoid j, Semigroup j) => Monoid (Journal j) where
93 mappend = journal_union
95 journal_union :: Semigroup j => Journal j -> Journal j -> Journal j
98 { journal_last_read_time = journal_last_read_time x `min` journal_last_read_time y
99 , journal_content = journal_content x <> journal_content y
100 , journal_includes = journal_includes x <> journal_includes y
103 journal_unions :: (Foldable f, Monoid j, Semigroup j) => f (Journal j) -> Journal j
104 journal_unions = foldl' (flip (<>)) journal
108 -- | Return the given accumulator folded over
109 -- the given 'Journal' and its 'journal_includes' 'Journal's.
110 journal_fold :: (Journal j -> a -> a) -> Journal j -> a -> a
111 journal_fold f j@Journal{journal_includes} a =
113 (flip $ journal_fold f) (f j a)
116 -- | Return the given accumulator folded over
117 -- the given 'Journal' and its 'journal_includes' 'Journal's.
118 journal_foldM :: Monad m => (Journal j -> a -> m a) -> Journal j -> a -> m a
119 journal_foldM f j@Journal{journal_includes} a = do
122 (flip $ journal_foldM f) ma
125 -- | Return the given accumulator folded with the given function
126 -- over the given 'Journal' and its 'journal_includes' 'Journal's.
127 journal_foldMap :: Monoid a => (Journal j -> a -> a) -> Journal j -> a -> a
128 journal_foldMap f j@(Journal{journal_includes}) =
129 f j `mappend` foldMap (journal_foldMap f) journal_includes
131 -- | Return the first non-'Nothing' value returned by the given function
132 -- when applied to the given 'Journal' or its 'journal_includes' 'Journal's,
133 -- with the parent 'Journal's.
134 journal_find :: (Journal j -> Maybe a) -> Journal j -> Maybe (a, [Journal j])
138 Just (a, path) -> Just (a, reverse path))
143 Just a -> Just (a, path)
146 foldMap (Monoid.First . (find_ (j:path))) $
149 -- | Return the given 'Journal' and its 'journal_includes' 'Journal's
150 -- mapped by the given function.
151 journal_traverse :: (Journal j -> Journal j) -> Journal j -> Journal j
154 j@Journal{journal_includes} ->
155 j{journal_includes = journal_traverse f <$> journal_includes})
158 -- | Return the 'Journal' recursively 'mappend'-ed
159 -- with its 'journal_includes', now empty.
160 journal_flatten :: (Monoid j, Semigroup j) => Journal j -> Journal j
161 journal_flatten jnl =
162 (mconcat $ (:) jnl $ journal_flatten <$>
163 journal_includes jnl) { journal_includes = [] }
167 newtype Journals j = Journals (Map CanonFile (Journal j))
168 deriving (Data, Eq, Show, Typeable)
169 type instance MT.Element (Journals j) = Journal j
171 instance MT.MonoFunctor (Journals j) where
172 omap f (Journals m) = Journals $ f `MT.omap` m
173 instance MT.MonoFoldable (Journals j) where
174 ofoldMap f (Journals m) = MT.ofoldMap f m
175 ofoldr f a (Journals m) = MT.ofoldr f a m
176 ofoldl' f a (Journals m) = MT.ofoldl' f a m
177 ofoldr1Ex f (Journals m) = MT.ofoldr1Ex f m
178 ofoldl1Ex' f (Journals m) = MT.ofoldl1Ex' f m
179 instance MT.MonoTraversable (Journals j) where
180 otraverse f (Journals m) = Journals <$> MT.otraverse f m
182 instance Functor Journals where
183 fmap f (Journals m) = Journals $ fmap f <$> m
184 instance Foldable Journals where
185 foldMap f (Journals m) = f `foldMap` Compose m
186 instance Traversable Journals where
187 traverse f (Journals m) =
188 Journals . getCompose <$> (f `traverse` Compose m)
194 -- ** Type 'JournalFile'
195 newtype JournalFile = JournalFile PathFile
196 deriving (Data, Eq, NFData, Ord, Show, Typeable)
197 unJournalFile :: JournalFile -> PathFile
198 unJournalFile (JournalFile fp) = fp
200 -- ** Type 'JournalFileCanon'
201 newtype JournalFileCanon = JournalFileCanon JournalFile
202 deriving (Data, Eq, NFData, Ord, Show, Typeable)
203 unJournalFileCanon :: JournalFileCanon -> JournalFile
204 unJournalFileCanon (JournalFileCanon jf) = jf
206 journalFileCanon :: JournalFile -> IO JournalFileCanon
207 journalFileCanon (JournalFile (PathFile fp)) =
208 JournalFileCanon . JournalFile . fromString
209 <$> IO.canonicalizePath fp
211 newtype Journals j = Journals (Forest (Journal j))
212 deriving (Data, Eq, Show, Typeable)
213 type instance MT.Element (Journals j) = Journal j
214 instance MT.MonoFunctor (Journals j) where
215 omap f (Journals m) = Journals $ f `MT.omap` m
216 instance MT.MonoFoldable (Journals j) where
217 ofoldMap f (Journals m) = MT.ofoldMap f m
218 ofoldr f a (Journals m) = MT.ofoldr f a m
219 ofoldl' f a (Journals m) = MT.ofoldl' f a m
220 ofoldr1Ex f (Journals m) = MT.ofoldr1Ex f m
221 ofoldl1Ex' f (Journals m) = MT.ofoldl1Ex' f m
222 instance MT.MonoTraversable (Journals j) where
223 otraverse f (Journals m) = Journals <$> MT.otraverse f m
226 instance Functor Journals where
227 fmap f (Journals m) = Journals $
228 getCompose $ getCompose . fmap f $ Compose (Compose m)
229 instance Foldable Journals where
230 foldMap f (Journals m) = foldMap f $ Compose (Compose m)
231 instance Traversable Journals where
232 traverse f (Journals m) =
233 Journals . getCompose . getCompose
234 <$> traverse f (Compose (Compose m))
236 instance Functor Journals where
237 fmap f (Journals m) = Journals $ fmap f <$> m
238 instance Foldable Journals where
239 foldMap f (Journals m) = f `foldMap` Compose m
240 instance Traversable Journals where
241 traverse f (Journals m) =
242 Journals . getCompose <$> (f `traverse` Compose m)
244 journals_flatten :: Journals j -> Journal j
245 journals_flatten js@(Journals m)
248 -- | Return the 'Journal' recursively 'mappend'-ed
249 -- with its 'journal_includes', now empty.
250 journal_flatten :: (Monoid j, Semigroup j) => Journal j -> Journal j
251 journal_flatten jnl =
252 (mconcat $ (:) jnl $ journal_flatten <$>
253 journal_includes jnl) { journal_includes = [] }
256 type instance MT.Element (TreeMap k a) = a
257 instance Ord k => MT.MonoFunctor (TreeMap k a)
258 instance Ord k => MT.MonoFoldable (TreeMap k a)
259 instance Ord k => MT.MonoTraversable (TreeMap k a)