h$pk      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~   None& %(-.0235678;>?%haspara'Common Aeson encoding/decoding options.hasparaAeson encoding/decoding options for uppercase constructor tag modifiersNone) %(-./0235678;<=>?haspara!Type encoding of a currency pair.1 values are constructed via the data constructor:CurrencyPair "EUR" "USD"EUR/USD and  instances are provided as well:Aeson.decode "{\"base\": \"EUR\", \"quote\": \"EUR\"}" :: Maybe CurrencyPair Just EUR/EUR'Aeson.encode (CurrencyPair "EUR" "USD")&"{\"base\":\"EUR\",\"quote\":\"USD\"}"haspara Base currency+ of the currency pair. Also referred to as counter currency.hasparaQuote currency+ of the currency pair. Also referred to as transaction currency.haspara:Type encoding for currency symbol values with a syntax of [A-Z]{3}[A-Z]*. values can be constructed via   that works in   context:/mkCurrencyError "EUR" :: Either T.Text Currency Right EUR ... or via   that works in  context:&mkCurrencyFail "EUR" :: Maybe CurrencyJust EURAn = instance is provided as well which is unsafe but convenient:"EUR" :: CurrencyEUR hasparaSmart constructor for  values within  context.,mkCurrencyError "" :: Either T.Text CurrencyLeft "Currency code error! Expecting at least 3 uppercase ASCII letters, but received: "-mkCurrencyError " " :: Either T.Text CurrencyLeft "Currency code error! Expecting at least 3 uppercase ASCII letters, but received: ".mkCurrencyError "AB" :: Either T.Text CurrencyLeft "Currency code error! Expecting at least 3 uppercase ASCII letters, but received: AB"1mkCurrencyError " ABC " :: Either T.Text CurrencyLeft "Currency code error! Expecting at least 3 uppercase ASCII letters, but received: ABC "/mkCurrencyError "ABC" :: Either T.Text Currency Right ABC hasparaSmart constructor for  values within  context.#mkCurrencyFail "" :: Maybe CurrencyNothing%mkCurrencyFail "US" :: Maybe CurrencyNothing&mkCurrencyFail "usd" :: Maybe CurrencyNothing&mkCurrencyFail "USD" :: Maybe CurrencyJust USD haspara"Parser that parses currency codes.,MP.runParser currencyCodeParser "Example" ""Left (ParseErrorBundle {bundleErrors = TrivialError 0 (Just EndOfInput) (fromList []) :| [], bundlePosState = PosState {pstateInput = "", pstateOffset = 0, pstateSourcePos = SourcePos {sourceName = "Example", sourceLine = Pos 1, sourceColumn = Pos 1}, pstateTabWidth = Pos 8, pstateLinePrefix = ""}})-MP.runParser currencyCodeParser "Example" " "Left (ParseErrorBundle {bundleErrors = TrivialError 0 (Just (Tokens (' ' :| ""))) (fromList []) :| [], bundlePosState = PosState {pstateInput = " ", pstateOffset = 0, pstateSourcePos = SourcePos {sourceName = "Example", sourceLine = Pos 1, sourceColumn = Pos 1}, pstateTabWidth = Pos 8, pstateLinePrefix = ""}})-MP.runParser currencyCodeParser "Example" "a"Left (ParseErrorBundle {bundleErrors = TrivialError 0 (Just (Tokens ('a' :| ""))) (fromList []) :| [], bundlePosState = PosState {pstateInput = "a", pstateOffset = 0, pstateSourcePos = SourcePos {sourceName = "Example", sourceLine = Pos 1, sourceColumn = Pos 1}, pstateTabWidth = Pos 8, pstateLinePrefix = ""}})-MP.runParser currencyCodeParser "Example" "A"Left (ParseErrorBundle {bundleErrors = TrivialError 1 (Just EndOfInput) (fromList []) :| [], bundlePosState = PosState {pstateInput = "A", pstateOffset = 0, pstateSourcePos = SourcePos {sourceName = "Example", sourceLine = Pos 1, sourceColumn = Pos 1}, pstateTabWidth = Pos 8, pstateLinePrefix = ""}}).MP.runParser currencyCodeParser "Example" "AB"Left (ParseErrorBundle {bundleErrors = TrivialError 2 (Just EndOfInput) (fromList []) :| [], bundlePosState = PosState {pstateInput = "AB", pstateOffset = 0, pstateSourcePos = SourcePos {sourceName = "Example", sourceLine = Pos 1, sourceColumn = Pos 1}, pstateTabWidth = Pos 8, pstateLinePrefix = ""}})/MP.runParser currencyCodeParser "Example" "ABC" Right "ABC"0MP.runParser currencyCodeParser "Example" "ABCD" Right "ABCD"2MP.runParser currencyCodeParser "Example" " ABCD "Left (ParseErrorBundle {bundleErrors = TrivialError 0 (Just (Tokens (' ' :| ""))) (fromList []) :| [], bundlePosState = PosState {pstateInput = " ABCD ", pstateOffset = 0, pstateSourcePos = SourcePos {sourceName = "Example", sourceLine = Pos 1, sourceColumn = Pos 1}, pstateTabWidth = Pos 8, pstateLinePrefix = ""}}) haspara Converts a  to a 2-tuple of  values.*toCurrencyTuple (CurrencyPair "EUR" "USD") (EUR,USD) hasparaConverts a 2-tuple of  values to a . fromCurrencyTuple ("EUR", "USD")EUR/USDhaspara instance for . Aeson.encode ("USD" :: Currency) "\"USD\""haspara instance for .3Aeson.eitherDecode "\"\"" :: Either String CurrencyLeft "Error in $: Currency code error! Expecting at least 3 uppercase ASCII letters, but received: "4Aeson.eitherDecode "\"A\"" :: Either String CurrencyLeft "Error in $: Currency code error! Expecting at least 3 uppercase ASCII letters, but received: A"5Aeson.eitherDecode "\"AB\"" :: Either String CurrencyLeft "Error in $: Currency code error! Expecting at least 3 uppercase ASCII letters, but received: AB"6Aeson.eitherDecode "\"ABC\"" :: Either String Currency Right ABC7Aeson.eitherDecode "\"ABCD\"" :: Either String Currency Right ABCDhaspara instance for ."USD" :: CurrencyUSDhaspara instance for ."USD" :: CurrencyUSDhaspara instance for .CurrencyPair "EUR" "USD"EUR/USD    None) %(-./0235678;<=>?!qhaspara!Type encoding for account values."This definition provides both the ! and an arbitrary object identifying the account. This arbitrary nature provides flexibility to use-site to use its own account identity and accompanying information when required.,let acc = Account AccountKindAsset (1 ::Int)Data.Aeson.encode acc#"{\"kind\":\"ASSET\",\"object\":1}"8Data.Aeson.decode @(Account Int) (Data.Aeson.encode acc)Just (Account {accountKind = AccountKindAsset, accountObject = 1})5Data.Aeson.decode (Data.Aeson.encode acc) == Just accTrue!haspara&Type encoding for ledger account type.This type covers both balance sheet and income statement account types: For balance sheet accounts:Asset (") Liability (#)Equity ($)For income statement accounts: Revenue (%) Expense (&)   and    instances, too: *Data.Aeson.decode @AccountKind "\"ASSET\""Just AccountKindAsset.Data.Aeson.decode @AccountKind "\"LIABILITY\""Just AccountKindLiability+Data.Aeson.decode @AccountKind "\"EQUITY\""Just AccountKindEquity,Data.Aeson.decode @AccountKind "\"REVENUE\""Just AccountKindRevenue,Data.Aeson.decode @AccountKind "\"EXPENSE\""Just AccountKindExpense"Data.Aeson.encode AccountKindAsset "\"ASSET\""&Data.Aeson.encode AccountKindLiability"\"LIABILITY\""#Data.Aeson.encode AccountKindEquity "\"EQUITY\""$Data.Aeson.encode AccountKindRevenue "\"REVENUE\""$Data.Aeson.encode AccountKindExpense "\"EXPENSE\""'haspara+Provides textual representation of a given !. accountKindText AccountKindAsset"Asset"$accountKindText AccountKindLiability "Liability"!accountKindText AccountKindEquity"Equity""accountKindText AccountKindRevenue "Revenue""accountKindText AccountKindExpense "Expense"  !&%$#"' !&%$#"' None' %(-./0235678;>?>q7hasparaType definition for unsigned 8 values.8hasparaType encoding for quantity values with a given scaling (digits after the decimal point).42 :: Quantity 04242 :: Quantity 142.042 :: Quantity 242.0041 + 1 :: Quantity 242.0043 - 1 :: Quantity 242.002 * 3 * 7 :: Quantity 242.00negate (-42) :: Quantity 242.00abs (-42) :: Quantity 242.00signum (-42) :: Quantity 2-1.00fromInteger 42 :: Quantity 242.00mkQuantity 0.415 :: Quantity 20.42mkQuantity 0.425 :: Quantity 20.425mkQuantityLossless 0.42 :: Either String (Quantity 2) Right 0.426mkQuantityLossless 0.415 :: Either String (Quantity 2)7Left "Underflow while trying to create quantity: 0.415";haspara Constructs 8 values from  values in a lossy way.This function uses @> in case that the lossless attempt fails. We could have used @ directly. However, @ is doing too much (see A). Therefore, we are first attempting a lossless construction (see <) and we fallback to @) in case the lossless construction fails.mkQuantity 0 :: Quantity 00mkQuantity 0 :: Quantity 10.0mkQuantity 0 :: Quantity 20.00mkQuantity 0.04 :: Quantity 10.0mkQuantity 0.05 :: Quantity 10.0mkQuantity 0.06 :: Quantity 10.1mkQuantity 0.14 :: Quantity 10.1mkQuantity 0.15 :: Quantity 10.2mkQuantity 0.16 :: Quantity 10.2mkQuantity 0.04 :: Quantity 20.04mkQuantity 0.05 :: Quantity 20.05mkQuantity 0.06 :: Quantity 20.06mkQuantity 0.14 :: Quantity 20.14mkQuantity 0.15 :: Quantity 20.15mkQuantity 0.16 :: Quantity 20.16mkQuantity 0.04 :: Quantity 30.040mkQuantity 0.05 :: Quantity 30.050mkQuantity 0.06 :: Quantity 30.060mkQuantity 0.14 :: Quantity 30.140mkQuantity 0.15 :: Quantity 30.150mkQuantity 0.16 :: Quantity 30.160<haspara Constructs 8 values from  values in a lossy way.2mkQuantityLossless 0 :: Either String (Quantity 0)Right 02mkQuantityLossless 0 :: Either String (Quantity 1) Right 0.02mkQuantityLossless 0 :: Either String (Quantity 2) Right 0.005mkQuantityLossless 0.04 :: Either String (Quantity 1)8Left "Underflow while trying to create quantity: 4.0e-2"5mkQuantityLossless 0.05 :: Either String (Quantity 1)8Left "Underflow while trying to create quantity: 5.0e-2"5mkQuantityLossless 0.06 :: Either String (Quantity 1)8Left "Underflow while trying to create quantity: 6.0e-2"5mkQuantityLossless 0.14 :: Either String (Quantity 1)6Left "Underflow while trying to create quantity: 0.14"5mkQuantityLossless 0.15 :: Either String (Quantity 1)6Left "Underflow while trying to create quantity: 0.15"5mkQuantityLossless 0.16 :: Either String (Quantity 1)6Left "Underflow while trying to create quantity: 0.16"5mkQuantityLossless 0.04 :: Either String (Quantity 2) Right 0.045mkQuantityLossless 0.05 :: Either String (Quantity 2) Right 0.055mkQuantityLossless 0.06 :: Either String (Quantity 2) Right 0.065mkQuantityLossless 0.14 :: Either String (Quantity 2) Right 0.145mkQuantityLossless 0.15 :: Either String (Quantity 2) Right 0.155mkQuantityLossless 0.16 :: Either String (Quantity 2) Right 0.165mkQuantityLossless 0.04 :: Either String (Quantity 3) Right 0.0405mkQuantityLossless 0.05 :: Either String (Quantity 3) Right 0.0505mkQuantityLossless 0.06 :: Either String (Quantity 3) Right 0.0605mkQuantityLossless 0.14 :: Either String (Quantity 3) Right 0.1405mkQuantityLossless 0.15 :: Either String (Quantity 3) Right 0.1505mkQuantityLossless 0.16 :: Either String (Quantity 3) Right 0.160=hasparaRounds given quantity by k digits.hasparaMultiplies two quantities with different scales and rounds back to the scale of the frst operand.times (mkQuantity 0.42 :: Quantity 2) (mkQuantity 0.42 :: Quantity 2)0.18?haspara0Multiplies two quantities with different scales.timesLossless (mkQuantity 0.42 :: Quantity 2) (mkQuantity 0.42 :: Quantity 2)0.1764@haspara$Auxiliary function for constructing 8 values.See ; why we need this function and why we haven't used it as the direct implementation of ;.Call-sites should avoid using this function directly due to its performance characteristics.AhasparaRounds a given scientific into a new scientific with given max digits after decimal point.$This uses half-even rounding method.roundScientific 0 0.40.0roundScientific 0 0.50.0roundScientific 0 0.61.0roundScientific 0 1.41.0roundScientific 0 1.52.0roundScientific 0 1.62.0roundScientific 1 0.040.0roundScientific 1 0.050.0roundScientific 1 0.060.1roundScientific 1 0.140.1roundScientific 1 0.150.2roundScientific 1 0.160.2roundScientific 1 3.6503.6roundScientific 1 3.7403.7roundScientific 1 3.7493.7roundScientific 1 3.7503.8roundScientific 1 3.7513.8roundScientific 1 3.7603.8roundScientific 1 (-3.650)-3.6roundScientific 1 (-3.740)-3.7roundScientific 1 (-3.749)-3.7roundScientific 1 (-3.750)-3.8roundScientific 1 (-3.751)-3.8roundScientific 1 (-3.760)-3.8;TODO: Refactor to improve the performance of this function.Bhaspara instance for 8.show (42 :: Quantity 2)"42.00"42 :: Quantity 242.00ChasparaFractional arithmetic over 8 values. import Numeric.Decimal?arithM (fromRational 0.42) :: Either SomeException (Quantity 2) Right 0.42arithM (fromRational 0.415) :: Either SomeException (Quantity 2)1Left PrecisionLoss (83 % 200) to 2 decimal spacesarithM $ (fromRational 0.84) / (fromRational 2) :: Either SomeException (Quantity 2) Right 0.42arithM $ (fromRational 0.42) / (fromRational 0) :: Either SomeException (Quantity 2)Left divide by zerolet a = 84 :: Quantity 2let b = 2 :: Quantity 2let c = 0 :: Quantity 2?arithM (Arith a / Arith b) :: Either SomeException (Quantity 2) Right 42.00arithM (Arith a / Arith b / Arith c) :: Either SomeException (Quantity 2)Left divide by zeroDhasparaNumeric arithmetic over 8 values. import Numeric.Decimallet a = Arith (mkQuantity 10) + Arith (mkQuantity 32) :: Arith (Quantity 2) arithMaybe a Just 42.004arithM (41 + 1) :: Either SomeException (Quantity 2) Right 42.004arithM (43 - 1) :: Either SomeException (Quantity 2) Right 42.007arithM (2 * 3 * 7) :: Either SomeException (Quantity 2) Right 42.007arithM (signum 42) :: Either SomeException (Quantity 2) Right 1.00:arithM (signum (-42)) :: Either SomeException (Quantity 2) Right -1.004arithM (abs 42) :: Either SomeException (Quantity 2) Right 42.007arithM (abs (-42)) :: Either SomeException (Quantity 2) Right 42.00?@A 89:7;<=>?@ANone) %(-./0235678;<=>?PMhaspara3Type encoding for FX rate quotation database for a .ShasparaType encoding for a dictionary-based FX rate quotation database for various  values.Thaspara:Type encoding for FX rate quotations with fixed precision.%An FX rate quotation is a 3-tuple of: +a currency pair the rate is quoted for, and-a date that the quotation is effective as of,0a (positive) rate as the value of the quotation.VhasparaCurrency pair of the FX rate.WhasparaActual date of the FX rate.Xhaspara%(Positive) rate value of the FX rate.YhasparaSmart constructor for T values within   context.The rate is expected to be a positive value. If it is not, the function will throw an error.mkFxQuoteError @(Either _) @2 "EUR" "USD" (read "2021-12-31") 1.16Right (MkFxQuote {fxQuotePair = EUR/USD, fxQuoteDate = 2021-12-31, fxQuoteRate = Refined 1.16})mkFxQuoteError @(Either _) @2 "EUR" "USD" (read "2021-12-31") (-1.16)Left "Can not create FX Rate. Error was: The predicate (GreaterThan 0) failed with the message: Value is not greater than 0\n"ZhasparaSmart constructor for T values within  context.The rate is expected to be a positive value. If it is not, the function will fail. >>> mkFxQuoteFail Maybe 2 EUR USD (read "2021-12-31") 1.16 Just (MkFxQuote {fxQuotePair = EUR/USD, fxQuoteDate = 2021-12-31, fxQuoteRate = Refined 1.16}) >>> mkFxQuoteFail Maybe 2 EUR USD% (read "2021-12-31") (-1.16) Nothing[hasparaUnsafe T constructor that s if it fails.7mkFxQuoteUnsafe @2 "EUR" "USD" (read "2021-12-31") 1.16MkFxQuote {fxQuotePair = EUR/USD, fxQuoteDate = 2021-12-31, fxQuoteRate = Refined 1.16}:mkFxQuoteUnsafe @2 "EUR" "USD" (read "2021-12-31") (-1.16)......Can not create FX Rate. Error was: The predicate (GreaterThan 0) failed with the message: Value is not greater than 0...\haspara9Attempts to find and return the FX quotation for a given  as of a give  in a given S.]haspara:Attempts to find and return the FX quotation as of a give  in a given M.^haspara)Returns empty FX rate quotation database.emptyFxQuoteDatabase @8 fromList []_haspara8Adds a list of FX rate quotations to the given database.&let database = emptyFxQuoteDatabase @8addFxQuotes [] database fromList []addFxQuotes [mkFxQuoteUnsafe @8 "EUR" "USD" (read "2021-01-31") 1.13] databasefromList [(EUR/USD,FxQuotePairDatabase {fxQuotePairDatabasePair = EUR/USD, fxQuotePairDatabaseTable = fromList [(2021-01-31,MkFxQuote {fxQuotePair = EUR/USD, fxQuoteDate = 2021-01-31, fxQuoteRate = Refined 1.13000000})], fxQuotePairDatabaseSince = 2021-01-31, fxQuotePairDatabaseUntil = 2021-01-31})]addFxQuotes [mkFxQuoteUnsafe @8 "EUR" "USD" (read "2021-01-31") 1.13, mkFxQuoteUnsafe @8 "USD" "EUR" (read "2021-01-31") 0.884956] databasefromList [(EUR/USD,FxQuotePairDatabase {fxQuotePairDatabasePair = EUR/USD, fxQuotePairDatabaseTable = fromList [(2021-01-31,MkFxQuote {fxQuotePair = EUR/USD, fxQuoteDate = 2021-01-31, fxQuoteRate = Refined 1.13000000})], fxQuotePairDatabaseSince = 2021-01-31, fxQuotePairDatabaseUntil = 2021-01-31}),(USD/EUR,FxQuotePairDatabase {fxQuotePairDatabasePair = USD/EUR, fxQuotePairDatabaseTable = fromList [(2021-01-31,MkFxQuote {fxQuotePair = USD/EUR, fxQuoteDate = 2021-01-31, fxQuoteRate = Refined 0.88495600})], fxQuotePairDatabaseSince = 2021-01-31, fxQuotePairDatabaseUntil = 2021-01-31})]`haspara0Adds an FX rate quotation to the given database.ahaspara;Initializes FX quote pair database with the given FX quote.bhasparaUpdates an existing FX quote pair database with the given FX quote.Yhaspara)Base currency (from) of the FX quotation.haspara(Quote currency (to) of the FX quotation.hasparaDate of the FX quotation.haspara+FX quotation rate, expected to be positive.Zhaspara)Base currency (from) of the FX quotation.haspara(Quote currency (to) of the FX quotation.hasparaDate of the FX quotation.haspara+FX quotation rate, expected to be positive.[haspara)Base currency (from) of the FX quotation.haspara(Quote currency (to) of the FX quotation.hasparaDate of the FX quotation.haspara+FX quotation rate, expected to be positive.\haspara/FX quotation database to perform the lookup on.haspara3Currency pair we are looking for the quotation for.haspara.Date the quotation we look for is valid as of.MNRQPOSTUXWVYZ[\]^_`abTUXWVYZ[SMNRQPO\]^_`abNone) %(-./0235678;<=>?X jhaspara*Type encoding of exceptions thrown by the   module.khasparaIndicates that we received a currency other than the expected currency.lhasparaIndicates that we received a currency other than the expected currency.mhasparaIndicates that we received a currency other than the expected currency.nhaspara$Type encoding of a monetary context.ohasparaConverts the given monetary value in one currency to another currency.Note that the conversion is performed with an FX rate quotation as of the date of the given monetary value.phasparaConverts the given monetary value in one currency to another currency as of the given date. The rule is:  convertAsofM  DATE2  CCY2 (Money  DATE1  CCY1  QTY1) === convertM  CCY2 (Money  DATE2  CCY1  QTY1) qhaspara(Type encoding for dated monetary values.'A dated monetary value is a 3-tuple of: 2a date when the monetary value is effective as of,'the currency of the monetary value, and#the quantity of the monetary value.vhasparaAttempts to convert the given q to another using the given T value.This function runs some guards before attempting to do the conversion: Base currency of the FX rate quotation should be the same as the currency of the monetary value, throws k otherwise.Date of the FX rate quotation should be equal to or greater than the date of the monetary value, throws l otherwise.(Rate of the FX rate quotation should be 16 if the base and quote quotation are same, throws m otherwise.khasparaExpected currencyhasparaReceived currencylhasparaDate on and onwards of interesthaspara Date receivedmhaspara6FX rate quotation that is interpreted as inconsistent. jmlknpoqrutsv qrutsnpovjmlkNone' %(-./0235678;>?\haspara7Type encoding of an economic increment/decrement event.The event explicitly carries the date and quantity information along with a parameterized, arbitrary object providing the source of the event. :set -XDataKindslet date = read "2021-01-01"let oid = 1 :: Int7let qty = $$(Refined.refineTH 42) :: UnsignedQuantity 2'let event = EventDecrement date oid qty"let json = Data.Aeson.encode eventjson"{\"qty\":42.0,\"type\":\"DECREMENT\",\"obj\":1,\"date\":\"2021-01-01\"}"%Data.Aeson.decode @(Event Int 2) json2Just (EventDecrement 2021-01-01 1 (Refined 42.00))$Data.Aeson.decode json == Just eventTruehasparaReturns the date of the event.haspara'Returns the source object of the event.hasparaNegates the event.hasparaSmart constuctor for  values.hasparaDate of the event.hasparaSource object of the event.hasparaQuantity of the event.None) %(-./0235678;<=>?ehasparaEncoding of a posting entry. :set -XDataKindsimport Refinedlet date = read "2021-01-01"let oid = 1 :: Int/let qty = $$(refineTH 42) :: UnsignedQuantity 2#let entry = EntryDebit date oid qtylet json = Aeson.encode entryjson"{\"qty\":42.0,\"type\":\"DEBIT\",\"obj\":1,\"date\":\"2021-01-01\"}"(Aeson.decode json :: Maybe (Entry Int 2).Just (EntryDebit 2021-01-01 1 (Refined 42.00))Aeson.decode json == Just entryTruehasparaType encoding for a posting.:set -XDataKindsimport Haspara.Accountingimport Refined$import qualified Data.Aeson as Aeson)import qualified Data.List.NonEmpty as NElet date = read "2021-01-01"let oid = 1 :: Int/let qty = $$(refineTH 42) :: UnsignedQuantity 2'let event = EventDecrement date oid qtylet account = Account AccountKindAsset ("Cash" :: String, 1 ::Int)9let posting = Posting . NE.fromList $ [(event, account)]let json = Aeson.encode postingjson"[[{\"qty\":42.0,\"type\":\"DECREMENT\",\"obj\":1,\"date\":\"2021-01-01\"},{\"kind\":\"ASSET\",\"object\":[\"Cash\",1]}]]"8Aeson.decode json :: Maybe (Posting (String, Int) Int 2)Just (Posting ((EventDecrement 2021-01-01 1 (Refined 42.00),Account {accountKind = AccountKindAsset, accountObject = ("Cash",1)}) :| []))!Aeson.decode json == Just postingTruehasparaType encoding of a ledger item.hasparaType encoding of a ledger.haspara&Creates a ledger from a given list of  values.hasparaAdds a new entry to a ledger.haspara*Returns the list of posting event sources.hasparaPosts an event.haspara&Returns the date of the posting entry.haspara*Returns the quantity of the posting entry.haspara/Returns the source object of the posting entry.haspara0Returns the debit quantity of the posting entry.haspara1Returns the credit quantity of the posting entry.hasparaConsumes an event and a type of account, and produces a posting entry."Note the following map as a guide:Kind of accountDebitCreditAssetIncreaseDecrease LiabilityDecreaseIncreaseEquity/CapitalDecreaseIncreaseIncome/RevenueDecreaseIncreaseExpenseCostDividendIncreaseDecreaseNone& %(-.0235678;>?f+ !"#$%&'+ !"#$%&' None& %(-.0235678;>?g: 789:;<=>?@AMNRQOPSTUXVWYZ[\]^_`abjmklnopqrustv None& %(-.0235678;>?khaspara Constructs a 8 value at compile-time using -XTemplateHaskell.!$$(quantityTH 0.00) :: Quantity 20.00!$$(quantityTH 0.09) :: Quantity 20.09"$$(quantityTH 0.009) :: Quantity 2...6..."Underflow while trying to create quantity: 9.0e-3"..."$$(quantityTH 0.009) :: Quantity 30.009haspara Constructs a  value at compile-time using -XTemplateHaskell.$$(currencyTH "USD")USD$$(currencyTH "usd")......Currency code error! Expecting at least 3 uppercase ASCII letters, but received: usd...haspara Constructs a  value at compile-time using -XTemplateHaskell.$$(currencyPairTH "EUR" "USD")EUR/USD$$(currencyPairTH "USD" "USD")USD/USD$$(currencyPairTH "USD" "eur")......Currency code error! Expecting at least 3 uppercase ASCII letters, but received: eur...None' %(-.0235678;>?k !"#$%&'()*+,--./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~~     &haspara-0.0.0.3-4zv1bokQoxCFAyBHZ5p8ozHaspara.Internal.AesonHaspara.CurrencyHaspara.Accounting.AccountHaspara.QuantityHaspara.FxQuoteHaspara.MonetaryHaspara.Accounting.EventHaspara.Accounting.Ledger Haspara.TH Data.AesonFromJSONToJSONHasparaMonetaryHaspara.Accounting Paths_hasparacommonAesonOptionsaesonOptionsForSingleTag CurrencyPaircurrencyPairBasecurrencyPairQuoteCurrency MkCurrency currencyCodemkCurrencyErrormkCurrencyFailcurrencyCodeParsertoCurrencyTuplefromCurrencyTuple$fToJSONCurrency$fFromJSONCurrency$fShowCurrency$fIsStringCurrency$fShowCurrencyPair$fToJSONCurrencyPair$fFromJSONCurrencyPair$fEqCurrencyPair$fGenericCurrencyPair$fOrdCurrencyPair$fLiftLiftedRepCurrencyPair $fEqCurrency$fHashableCurrency $fOrdCurrency$fLiftLiftedRepCurrencyAccount accountKind accountObject AccountKindAccountKindAssetAccountKindLiabilityAccountKindEquityAccountKindRevenueAccountKindExpenseaccountKindText$fToJSONAccountKind$fFromJSONAccountKind$fHashableAccountKind$fToJSONAccount$fFromJSONAccount$fHashableAccount $fEqAccount$fGenericAccount $fOrdAccount $fShowAccount$fEnumAccountKind$fEqAccountKind$fGenericAccountKind$fOrdAccountKind$fShowAccountKindUnsignedQuantityQuantity MkQuantity unQuantity mkQuantitymkQuantityLossless roundQuantitytimes timesLossless mkQuantityAuxroundScientific$fShowQuantity$fFractionalArith $fNumArith$fToJSONQuantity$fFromJSONQuantity $fEqQuantity $fOrdQuantity$fGenericQuantity $fNumQuantity$fLiftLiftedRepQuantity$fLiftLiftedRepDecimalFxQuotePairDatabasefxQuotePairDatabasePairfxQuotePairDatabaseTablefxQuotePairDatabaseSincefxQuotePairDatabaseUntilFxQuoteDatabaseFxQuote MkFxQuote fxQuotePair fxQuoteDate fxQuoteRatemkFxQuoteError mkFxQuoteFailmkFxQuoteUnsafe findFxQuotefindFxQuoteAuxemptyFxQuoteDatabase addFxQuotes addFxQuoteinitFxQuotePairDatabaseupdateFxQuotePairDatabase$fToJSONFxQuote$fFromJSONFxQuote$fShowFxQuotePairDatabase $fEqFxQuote$fGenericFxQuote $fOrdFxQuote $fShowFxQuoteMonetaryExceptionIncompatibleCurrenciesExceptionIncompatibleDatesExceptionInconsistentFxQuoteExceptionconvertM convertAsofMMoney moneyDate moneyCurrency moneyQuantityconvert $fToJSONMoney$fFromJSONMoney$fExceptionMonetaryException $fEqMoney$fGenericMoney $fOrdMoney $fShowMoney$fShowMonetaryExceptionEventEventDecrementEventIncrement eventDate eventObject negateEventmkEvent $fToJSONEvent$fFromJSONEvent $fEqEvent $fOrdEvent $fShowEventEntry EntryDebit EntryCreditPosting LedgerItemledgerItemEntryledgerItemBalanceLedger ledgerAccount ledgerOpening ledgerClosing ledgerRunningmkLedgeraddEntry postingEventspost entryDate entryQuantity entryObject entryDebit entryCredit buildEntry$fToJSONPosting$fFromJSONPosting $fToJSONEntry$fFromJSONEntry$fToJSONLedgerItem$fFromJSONLedgerItem$fToJSONLedger$fFromJSONLedger $fEqLedger$fGenericLedger $fOrdLedger $fShowLedger$fEqLedgerItem$fGenericLedgerItem$fOrdLedgerItem$fShowLedgerItem $fEqEntry $fOrdEntry $fShowEntry $fEqPosting$fGenericPosting $fOrdPosting $fShowPosting quantityTH currencyTHcurrencyPairTH"aeson-2.0.3.0-PHa5hlOiN2tOJTVv776ZData.Aeson.Types.FromJSONData.Aeson.Types.ToJSON mtl-2.2.2Control.Monad.Error.Class MonadError#text-1.2.5.0-IEal7YJCEpPE23BnjRa8JhData.Text.InternalTextbaseControl.Monad.Fail MonadFail Data.StringIsStringGHC.ShowShow)scientific-0.3.7.0-1cuz7K99vCtLQ884HOpguaData.Scientific Scientifictemplate-haskellLanguage.Haskell.TH.SyntaxLiftGHC.Errerror time-1.9.3Data.Time.Calendar.DaysDayversion getBinDir getLibDir getDynLibDir getDataDir getLibexecDir getSysconfDirgetDataFileName