packages feed

exchangealgebra-0.5.1.0: src/ExchangeAlgebra/Journal/Transfer/Rule.hs

{- |
Module      : ExchangeAlgebra.Journal.Transfer.Rule
Description : Note-preserving transfer entries and closing across notes.

Use a qualified import to distinguish these functions from the Algebra API:

> import qualified ExchangeAlgebra.Journal.Transfer.Rule as Transfer

Definition 9 and laws L1-L5 are documented in
"ExchangeAlgebra.Algebra.Transfer.Rule". Transfer lifts that operation over
notes; closing reads the combined ledger and returns an unannotated algebra
through 'Either'.
-}
module ExchangeAlgebra.Journal.Transfer.Rule
    ( transferEntries
    , closingEntries
    ) where

import qualified Data.HashMap.Strict as Map
import           ExchangeAlgebra.Algebra (Alg, HatVal, HatBaseClass, ExBaseClass)
import           ExchangeAlgebra.Algebra.Transfer.Rule (TransferRules, TransferApplyError)
import qualified ExchangeAlgebra.Algebra.Transfer.Rule as Rule
import           ExchangeAlgebra.Journal (Journal, Note, toMap, fromMap, toAlg)

-- | Generate additional entries under the same notes as their sources.
-- Each note is processed in the traversal order of 'toMap'. The first failure
-- aborts the whole operation; no partial Journal is returned. This order is
-- an implementation traversal, not a chronological ordering of notes.
-- Input posting values must be valid and finite. No @bar@ is applied.
transferEntries :: (Note n, HatVal v, HatBaseClass b)
                => TransferRules v b
                -> Journal n v b
                -> Either (TransferApplyError v b) (Journal n v b)
transferEntries rules journal = fromMap . Map.fromList
                             <$> traverse apply (Map.toList (toMap journal))
  where
    apply (note, algebra) = do
        entries <- Rule.transferEntries rules algebra
        pure (note, entries)

-- | Read net balances across all notes and return unannotated closing entries.
-- The input must include only postings through the closing date; 'toAlg'
-- does not select a period. Earlier periods must already have their closing
-- entries included. Attach the settlement note with @(.|)@ at the call site.
-- Source sequences are folded per base by the Algebra operation, without
-- a tolerance or implicit @bar@; small floating-point residues can remain.
-- Finite, non-negative inputs normally yield 'Right'; 'Left' occurs only
-- when a side's sum exceeds the value type's range. The Algebra operation
-- checks totals and differences and reports the first failing base in
-- ascending order, with Hat/Not normalized to Not. No partial result is returned.
closingEntries :: (Note n, HatVal v, ExBaseClass b)
               => Journal n v b -> Either (TransferApplyError v b) (Alg v b)
closingEntries = Rule.closingEntries . toAlg