Îõ³h$T-Q ú      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyNone ;?Îq hasparaType encoding for currencies.hasparaSmart constructor for  values within z context.%currency "" :: Either String CurrencyÙLeft "Currency code error! Expecting at least 3 uppercase characters, but received: \"\""¤cy " " :: Either String CurrencyÚLeft "Currency code error! Expecting at least 3 uppercase characters, but received: \" \""'currency "AB" :: Either String CurrencyÛLeft "Currency code error! Expecting at least 3 uppercase characters, but received: \"AB\""*currency " ABC " :: Either String CurrencyÞLeft "Currency code error! Expecting at least 3 uppercase characters, but received: \" ABC \""(currency "ABC" :: Either String Currency Right ABChasparaSmart constructor for  values within { context.!currencyFail "" :: Maybe CurrencyNothing#currencyFail "US" :: Maybe CurrencyNothing$currencyFail "usd" :: Maybe CurrencyNothing$currencyFail "USD" :: Maybe CurrencyJust USDhaspara"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"haspara| instance for .Aeson.encode (MkCurrency "USD") "\"USD\""haspara} instance for .3Aeson.eitherDecode "\"\"" :: Either String CurrencyåLeft "Error in $: Currency code error! Expecting at least 3 uppercase characters, but received: \"\""6Aeson.eitherDecode "\"ABC\"" :: Either String Currency Right ABChaspara~ instance for ."USD" :: CurrencyUSDhaspara instance for .MkCurrency "USD"USDhaspara instance for currency pairs.MkCurrencyPair ("EUR", "USD")EUR/USD  None «   None ÎæhasparaType encoding for date values.%This is a convenience wrapper around Day7 type. It helps us to avoid defining orphan instances.haspara Builds a  from a given Day.fromDay (read "2021-01-01") 2021-01-01haspara Builds a ; from a given year, month and day as in Gregorian calendar.fromYMD 2021 1 1 2021-01-01hasparaAttempts to parse and return  from a given € with ISO format.%fromString "2021-01-01" :: Maybe DateJust 2021-01-01#fromString "20210101" :: Maybe DateNothing hasparaAttempts to parse and return  from a given € with given date format.9fromFormattedString "%Y-%m-%d" "2021-01-01" :: Maybe DateJust 2021-01-015fromFormattedString "%Y%m%d" "20210101" :: Maybe DateJust 2021-01-013fromFormattedString "%Y%m%d" "202101" :: Maybe DateNothing!hasparaAttempts to parse and return  from a given  with ISO format.#fromText "2021-01-01" :: Maybe DateJust 2021-01-01!fromText "20210101" :: Maybe DateNothing"hasparaAttempts to parse and return  from a given  with ISO format.7fromFormattedText "%Y-%m-%d" "2021-01-01" :: Maybe DateJust 2021-01-013fromFormattedText "%Y%m%d" "20210101" :: Maybe DateJust 2021-01-011fromFormattedText "%Y%m%d" "202101" :: Maybe DateNothing#haspara Converts  value to a ‚ value.toDay (read "2021-01-01") 2021-01-01$haspara Converts + value to a 3-tuple of year, month and day.toYMD (read "2020-12-31") (2020,12,31)%haspara Converts  value into a € value with ISO format.toString (read "2021-01-01") "2021-01-01"&haspara Converts  value into a € value with the given format.0toFormattedString "%Y-%m-%d" (read "2021-01-01") "2021-01-01"0toFormattedString "%d/%m/%Y" (read "2021-01-01") "01/01/2021"'haspara Converts  value into a  value with ISO format.toText (read "2021-01-01") "2021-01-01"(haspara Converts  value into a  value with the given format..toFormattedText "%Y-%m-%d" (read "2021-01-01") "2021-01-01".toFormattedText "%d/%m/%Y" (read "2021-01-01") "01/01/2021")hasparaAdds (or subtracts) some days.addDays (-1) $ fromYMD 2021 1 1 2020-12-31+addDays 1 $ addDays (-1) $ fromYMD 2021 1 1 2021-01-01*haspara| instance for .)Aeson.encode (MkDate (read "2021-01-01"))"\"2021-01-01\""+haspara} instance for .+Aeson.decode "\"2020-12-31\"" :: Maybe DateJust 2020-12-31,haspara instance for .fromYMD 2020 12 31 2020-12-31-hasparaƒ instance for .read "2021-01-01" :: Date 2021-01-01$read "Just 2021-01-01" :: Maybe DateJust 2021-01-01.haspara„ instance for . !"#$%&'() !"#$%&'() None " !"#$%&'() !"#$%&'()None Î2haspara-Type encoding for a lookup table from entity 3s to corresponding entities.#data A = A Int String deriving Showtype IdA = Id A Intlet a1 = A 1 "a1"let a2 = A 2 "a2"let a3 = A 3 "a3"Îlet table = HM.fromList [(Id 1, a1), (Id 2, a2), (Id 3, a3)] :: IdLookup A IntHM.lookup (Id 1) tableJust (A 1 "a1")3haspara%Type encoding for entity identifiers.This encoding allows us to provide a phantom type for distinguishing between identifiers of varying types and an underlying identifier type. For example: data A = A data B = B data C = Ctype IdA = Id A Inttype IdB = Id B Inttype IdC = Id C Stringlet idA = Id 1 :: IdAlet idB = Id 1 :: IdBlet idC = Id "C1" :: IdCidA1idB1idC"C1" idA == idATrueÄ-- idA == idB -- Compile error as: Couldn't match type ˜@B™@ with ˜@A™@*Hashes, on the otherhand, can be compared:import Data.Hashablehash idA == hash idBTrue23453452 None -23453452None /28;>?ÀÉÎÖ×Ù;L<hasparaÞType encoding for common quantity values with 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.00quantity 0.415 :: Quantity 20.42quantity 0.425 :: Quantity 20.423quantityLossless 0.42 :: Either String (Quantity 2) Right 0.424quantityLossless 0.415 :: Either String (Quantity 2)7Left "Underflow while trying to create quantity: 0.415"?haspara Constructs < 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 EÄ). Therefore, we are first attempting a lossless construction (see A) and we fallback to @* in case the lossless construction fails.quantity 0 :: Quantity 00quantity 0 :: Quantity 10.0quantity 0 :: Quantity 20.00quantity 0.04 :: Quantity 10.0quantity 0.05 :: Quantity 10.0quantity 0.06 :: Quantity 10.1quantity 0.14 :: Quantity 10.1quantity 0.15 :: Quantity 10.2quantity 0.16 :: Quantity 10.2quantity 0.04 :: Quantity 20.04quantity 0.05 :: Quantity 20.05quantity 0.06 :: Quantity 20.06quantity 0.14 :: Quantity 20.14quantity 0.15 :: Quantity 20.15quantity 0.16 :: Quantity 20.16quantity 0.04 :: Quantity 30.040quantity 0.05 :: Quantity 30.050quantity 0.06 :: Quantity 30.060quantity 0.14 :: Quantity 30.140quantity 0.15 :: Quantity 30.150quantity 0.16 :: Quantity 30.160@hasparaAuxiliary function for ? implementation.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.Ahaspara Constructs < values from … values in a lossy way.0quantityLossless 0 :: Either String (Quantity 0)Right 00quantityLossless 0 :: Either String (Quantity 1) Right 0.00quantityLossless 0 :: Either String (Quantity 2) Right 0.003quantityLossless 0.04 :: Either String (Quantity 1)8Left "Underflow while trying to create quantity: 4.0e-2"3quantityLossless 0.05 :: Either String (Quantity 1)8Left "Underflow while trying to create quantity: 5.0e-2"3quantityLossless 0.06 :: Either String (Quantity 1)8Left "Underflow while trying to create quantity: 6.0e-2"3quantityLossless 0.14 :: Either String (Quantity 1)6Left "Underflow while trying to create quantity: 0.14"3quantityLossless 0.15 :: Either String (Quantity 1)6Left "Underflow while trying to create quantity: 0.15"3quantityLossless 0.16 :: Either String (Quantity 1)6Left "Underflow while trying to create quantity: 0.16"3quantityLossless 0.04 :: Either String (Quantity 2) Right 0.043quantityLossless 0.05 :: Either String (Quantity 2) Right 0.053quantityLossless 0.06 :: Either String (Quantity 2) Right 0.063quantityLossless 0.14 :: Either String (Quantity 2) Right 0.143quantityLossless 0.15 :: Either String (Quantity 2) Right 0.153quantityLossless 0.16 :: Either String (Quantity 2) Right 0.163quantityLossless 0.04 :: Either String (Quantity 3) Right 0.0403quantityLossless 0.05 :: Either String (Quantity 3) Right 0.0503quantityLossless 0.06 :: Either String (Quantity 3) Right 0.0603quantityLossless 0.14 :: Either String (Quantity 3) Right 0.1403quantityLossless 0.15 :: Either String (Quantity 3) Right 0.1503quantityLossless 0.16 :: Either String (Quantity 3) Right 0.160BhasparaRounds given quantity by k digits.:roundQuantity (quantity 0.415 :: Quantity 3) :: Quantity 20.42:roundQuantity (quantity 0.425 :: Quantity 3) :: Quantity 20.42ChasparaáMultiplies two quantities with different scales and rounds back to the scale of the frst operand.Átimes (quantity 0.42 :: Quantity 2) (quantity 0.42 :: Quantity 2)0.18Dhaspara0Multiplies two quantities with different scales.ÉtimesLossless (quantity 0.42 :: Quantity 2) (quantity 0.42 :: Quantity 2)0.1764EhasparaÛRounds 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.Fhaspara instance for <.show (42 :: Quantity 2)"42.00"42 :: Quantity 242.00GhasparaFractional arithmetic over < values. import Numeric.Decimal?arithM (fromRational 0.42) :: Either SomeException (Quantity 2) Right 0.42ÀarithM (fromRational 0.415) :: Either SomeException (Quantity 2)1Left PrecisionLoss (83 % 200) to 2 decimal spacesÔarithM $ (fromRational 0.84) / (fromRational 2) :: Either SomeException (Quantity 2) Right 0.42ÔarithM $ (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.00ÉarithM (Arith a / Arith b / Arith c) :: Either SomeException (Quantity 2)Left divide by zeroHhasparaNumeric arithmetic over < values. import Numeric.DecimalÇlet a = Arith (quantity 10) + Arith (quantity 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?@ABCDE <=>?@ABCDENone /?ÉFÏ QhasparaType encoding for FX rates.ShasparaActual date of the FX rate.ThasparaCurrency pair of the FX rate.UhasparaRate value of the FX rate.VhasparaSmart constructor for Q values within z context.WhasparaSmart constructor for Q values within { context.XhasparaUnsafe Q constructor that ‡s if it fails.Yhaspara| instance for :set -XDataKindsÊlet rate = fxquoteUnsafe (read "2021-01-01") "USD" "SGD" 1.35 :: FXQuote 2Aeson.encode rateË"{\"ccy2\":\"SGD\",\"date\":\"2021-01-01\",\"rate\":1.35,\"ccy1\":\"USD\"}"Zhaspara} instance for  :set -XDataKinds‚Aeson.eitherDecode "{\"date\": \"2021-01-01\", \"ccy1\": \"USD\", \"ccy2\": \"SGD\", \"rate\": 1.35}" :: Either String (FXQuote 2)%Right ("USD/SGD","2021-01-01","1.35")ƒAeson.eitherDecode "{\"date\": \"2021-01-01\", \"ccy1\": \"USD\", \"ccy2\": \"SGD\", \"rate\": 1.354}" :: Either String (FXQuote 2)%Right ("USD/SGD","2021-01-01","1.35")ƒAeson.eitherDecode "{\"date\": \"2021-01-01\", \"ccy1\": \"USD\", \"ccy2\": \"SGD\", \"rate\": 1.355}" :: Either String (FXQuote 2)%Right ("USD/SGD","2021-01-01","1.36")ƒAeson.eitherDecode "{\"date\": \"2021-01-01\", \"ccy1\": \"USD\", \"ccy2\": \"SGD\", \"rate\": 1.356}" :: Either String (FXQuote 2)%Right ("USD/SGD","2021-01-01","1.36")ƒAeson.eitherDecode "{\"date\": \"2021-01-01\", \"ccy1\": \"USD\", \"ccy2\": \"SGD\", \"rate\": 1.364}" :: Either String (FXQuote 2)%Right ("USD/SGD","2021-01-01","1.36")ƒAeson.eitherDecode "{\"date\": \"2021-01-01\", \"ccy1\": \"USD\", \"ccy2\": \"SGD\", \"rate\": 1.365}" :: Either String (FXQuote 2)%Right ("USD/SGD","2021-01-01","1.36")ƒAeson.eitherDecode "{\"date\": \"2021-01-01\", \"ccy1\": \"USD\", \"ccy2\": \"SGD\", \"rate\": 1.366}" :: Either String (FXQuote 2)%Right ("USD/SGD","2021-01-01","1.37")‚Aeson.eitherDecode "{\"date\": \"2021-01-01\", \"ccy1\": \"USD\", \"ccy2\": \"USD\", \"rate\": 1.35}" :: Either String (FXQuote 2)ôLeft "Error in $: Can not create FX Rate. Error was: Can not create currency pair from same currencies: USD and USD"ƒAeson.eitherDecode "{\"date\": \"2021-01-01\", \"ccy1\": \"USD\", \"ccy2\": \"SGD\", \"rate\": -1.35}" :: Either String (FXQuote 2)ŒLeft "Error in $: Can not create FX Rate. Error was: The predicate (GreaterThan 0) failed with the message: Value is not greater than 0\n"VhasparaDate of the FX rate.haspara%First currency (from) of the FX rate.haspara$Second currency (to) of the FX rate.hasparaFX rate value.WhasparaDate of the FX rate.haspara%First currency (from) of the FX rate.haspara$Second currency (to) of the FX rate.hasparaFX rate value.XhasparaDate of the FX rate.haspara%First currency (from) of the FX rate.haspara$Second currency (to) of the FX rate.hasparaFX rate value.QRUTSVWXQRUTSVWXNone /ÉKÚghasparaConverts the given ^6 value to another given currency with the given rate.import Haspara*let eur = either error id $ currency "EUR"*let usd = either error id $ currency "USD"$let date = read "2021-01-01" :: DateÈlet eurmoney = mkMoney date eur (quantity 0.42 :: Quantity 2) :: Money 2/convert eurmoney eur (quantity 1 :: Quantity 4)MoneySome 2021-01-01 EUR 0.42/convert eurmoney usd (quantity 1 :: Quantity 4)MoneySome 2021-01-01 USD 0.424convert eurmoney usd (quantity 1.1516 :: Quantity 4)MoneySome 2021-01-01 USD 0.48hhasparaConverts the given ^+ value to another currency with the given Q.ihaspara| instance for ^.ÓAeson.encode (MoneySome (read "2021-01-01") ("USD" :: Currency) (42 :: Quantity 0))6"{\"qty\":42,\"ccy\":\"USD\",\"date\":\"2021-01-01\"}"#Aeson.encode (MoneyZero :: Money 2)"0"*Aeson.encode (MoneyFail "oops" :: Money 2)"{\"error\":\"oops\"}"jhaspara} instance for ^.ÖAeson.decode "{\"qty\":42,\"ccy\":\"USD\",\"date\":\"2021-01-01\"}" :: Maybe (Money 2)%Just (MoneySome 2021-01-01 USD 42.00)#Aeson.decode "0" :: Maybe (Money 2)Just MoneyZero7Aeson.decode "{\"error\": \"oops\"}" :: Maybe (Money 2)Just (MoneyFail "oops") ^a`_bcdefgh ^a`_bcdefghNone /ÉL nosrqptuv tnosrqpuv None LAQUSTVWnopqrstuQSTUVWtnopqrsu None L{ ^_`abcdefgh ^_`adefbcghNone L¯<>?ABCD<>?ABCDNone LÛ<  !"#$%&'()2345<>?ABCDQUSTVW^a_`bcdefghnosrpqtuNone ÙPÝwhaspara Constructs a < value at compile-time using -XTemplateHaskell.:set -XDataKinds!$$(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.009xhaspara Constructs a  value at compile-time using -XTemplateHaskell.$$(currencyTH "USD")USD$$(currencyTH "usd")...Ö...Currency code error! Expecting at least 3 uppercase characters, but received: "usd"...yhaspara Constructs a  value at compile-time using -XTemplateHaskell.$$(currencyPairTH "EUR" "USD")EUR/USD$$(currencyPairTH "USD" "USD")...Á...Can not create currency pair from same currencies: USD and USD...$$(currencyPairTH "USD" "eur")...Ö...Currency code error! Expecting at least 3 uppercase characters, but received: "eur"...wxywxy Safe-Inferred Q ˆ‰Š‹ŒŽ !"#$%&'()*+,-./0123456789:;<=>?@ABCDDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“Œ”•Œ–—Œ˜™š›œžŸŒ ¡¢£¤¥¦§¨©ªŒ«¬­®¯°±²³´µ&haspara-0.0.0.0-2g1Vaq2zya97oIptorNIyAHaspara.Internal.CurrencyHaspara.Internal.DateHaspara.Internal.IdHaspara.Internal.QuantityHaspara.Internal.FXQuoteHaspara.Internal.Money Haspara.Internal.FXQuoteDatabase Haspara.THHaspara.Currency Haspara.Date Haspara.IdHaspara.FXQuote Haspara.MoneyHaspara.QuantityHaspara Paths_haspara CurrencyPairMkCurrencyPairunCurrencyPairCurrency MkCurrency currencyCodecurrency currencyFailcurrencyCodeParsertoTuple baseCurrency quoteCurrency currencyPaircurrencyPairFail$fToJSONCurrency$fFromJSONCurrency$fIsStringCurrency$fShowCurrency$fShowCurrencyPair$fEqCurrencyPair$fHashableCurrencyPair$fOrdCurrencyPair$fLiftLiftedRepCurrencyPair $fEqCurrency$fHashableCurrency $fOrdCurrency$fLiftLiftedRepCurrencyDateMkDatefromDayfromYMD fromStringfromFormattedStringfromTextfromFormattedTexttoDaytoYMDtoStringtoFormattedStringtoTexttoFormattedTextaddDays $fToJSONDate$fFromJSONDate $fShowDate $fReadDate$fHashableDate$fEqDate $fEnumDate $fOrdDateIdLookupIdunId $fToJSONId $fFromJSONId$fShowId$fEqId$fOrdId $fHashableIdQuantity MkQuantity unQuantityquantity quantityAuxquantityLossless roundQuantitytimes timesLosslessroundScientific$fShowQuantity$fFractionalArith $fNumArith$fToJSONQuantity$fFromJSONQuantity $fEqQuantity $fOrdQuantity$fGenericQuantity $fNumQuantity$fLiftLiftedRepQuantity$fLiftLiftedRepDecimalFXQuote MkFXQuote fxQuoteDate fxQuotePair fxQuoteRatefxquote fxquoteFail fxquoteUnsafe$fToJSONFXQuote$fFromJSONFXQuote $fShowFXQuote $fEqFXQuote $fOrdFXQuoteMoney MoneySome MoneyZero MoneyFailmkMoneymkMoneyFromScientific moneyDate moneyCurrency moneyQuantityconvertconvertWithQuote $fToJSONMoney$fFromJSONMoney $fEqMoney $fOrdMoney $fShowMoneyFXQuotePairDatabasefxQuotePairDatabasePairfxQuotePairDatabaseTablefxQuotePairDatabaseSincefxQuotePairDatabaseUntilFXQuoteDatabase findFXQuotefindFXQuoteAux quantityTH currencyTHcurrencyPairTH mtl-2.2.2Control.Monad.Error.Class MonadErrorbaseControl.Monad.Fail MonadFail$aeson-1.5.6.0-6q3F4UvhVOcAvcXT4WASpUData.Aeson.Types.ToJSONToJSONData.Aeson.Types.FromJSONFromJSON Data.StringIsStringGHC.ShowShowGHC.BaseString#text-1.2.5.0-LkZshtXQYe46X71oLWingHData.Text.InternalText time-1.9.3Data.Time.Calendar.DaysDayGHC.ReadRead'hashable-1.3.5.0-1tOwgLRyyokHOhyIXuRuxyData.Hashable.ClassHashable)scientific-0.3.7.0-HweDyyDQK8kCSs1SatrZFIData.Scientific Scientifictemplate-haskellLanguage.Haskell.TH.SyntaxLiftGHC.Errerrorversion getBinDir getLibDir getDynLibDir getDataDir getLibexecDir getSysconfDirgetDataFileName