mirror of
https://github.com/digital-asset/daml.git
synced 2024-11-10 10:46:11 +03:00
Start adding Numeric to the standard library. (#2950)
* Numeric implementation * Dealing with all sorts of numeric literals. * Fix DA.Generics * Reduce code duplication with IF_NUMERIC * Simplify Prelude with IF_NUMERIC * Fix daml-lf validation for MUL_NUMERIC and DIV_NUMERIC
This commit is contained in:
parent
5eb76eef91
commit
46051e8d11
@ -8,6 +8,7 @@ module DA.Daml.LF.Ast.Numeric
|
||||
, numeric
|
||||
, numericScale
|
||||
, numericMaxScale
|
||||
, numericFromRational
|
||||
, numericFromDecimal
|
||||
) where
|
||||
|
||||
@ -48,6 +49,10 @@ numeric s m
|
||||
| m > numericMaxMantissa = error "numeric error: mantissa too large"
|
||||
| otherwise = Numeric $ Decimal (fromIntegral s) m
|
||||
|
||||
-- | Convert a rational number into a Numeric.
|
||||
numericFromRational :: Rational -> Numeric
|
||||
numericFromRational r = Numeric (fromRational r)
|
||||
|
||||
-- | Upper bound for numeric scale (inclusive).
|
||||
numericMaxScale :: Natural
|
||||
numericMaxScale = 37
|
||||
|
@ -95,7 +95,7 @@ import Control.Monad.Reader
|
||||
import Control.Monad.State.Strict
|
||||
import DA.Daml.LF.Ast as LF
|
||||
import DA.Daml.LF.Ast.Type as LF
|
||||
import DA.Daml.LF.Ast.Numeric (numericFromDecimal)
|
||||
import DA.Daml.LF.Ast.Numeric
|
||||
import Data.Data hiding (TyCon)
|
||||
import Data.Foldable (foldlM)
|
||||
import Data.Int
|
||||
@ -211,8 +211,9 @@ convertInt64 x
|
||||
| otherwise =
|
||||
unsupported "Int literal out of bounds" (negate x)
|
||||
|
||||
convertRational :: Env -> Integer -> Integer -> ConvertM LF.Expr
|
||||
convertRational env num denom
|
||||
-- | Convert a rational number into a (legacy) Decimal literal.
|
||||
convertRationalDecimal :: Env -> Integer -> Integer -> ConvertM LF.Expr
|
||||
convertRationalDecimal env num denom
|
||||
=
|
||||
-- the denominator needs to be a divisor of 10^10.
|
||||
-- num % denom * 10^10 needs to fit within a 128bit signed number.
|
||||
@ -235,6 +236,67 @@ convertRational env num denom
|
||||
upperBound128Bit = 10 ^ (38 :: Integer)
|
||||
maxPrecision = 10 :: Integer
|
||||
|
||||
-- | Convert a rational number into a fixed scale Numeric literal. We check
|
||||
-- that the scale is in bounds, and the number can be represented without
|
||||
-- overflow or loss of precision.
|
||||
convertRationalNumericMono :: Env -> Integer -> Integer -> Integer -> ConvertM LF.Expr
|
||||
convertRationalNumericMono env scale num denom =
|
||||
if | scale < 0 || scale > 37 ->
|
||||
unsupported
|
||||
("Tried to construct value of type Numeric " ++ show scale ++ ", but scale is out of bounds. Scale must be between 0 through 37, not " ++ show scale ++ ".")
|
||||
scale
|
||||
|
||||
| abs (r * 10 ^ scale) >= upperBound128Bit ->
|
||||
unsupported
|
||||
("Rational is out of bounds: " ++
|
||||
show ((fromInteger num / fromInteger denom) :: Double) ++
|
||||
". The range of values representable by the Numeric " ++ show scale ++ " type is -10^" ++ show (38-scale) ++ " + 1 through 10^" ++ show (38-scale) ++ " - 1.")
|
||||
(num, denom)
|
||||
|
||||
| (num * 10^scale) `mod` denom /= 0 ->
|
||||
unsupported
|
||||
("Rational is out of bounds: it cannot be represented without loss of precision. " ++
|
||||
show ((fromInteger num / fromInteger denom) :: Double) ++
|
||||
". Maximum precision for the Numeric " ++ show scale ++ " type is 10^-" ++ show scale ++ ".")
|
||||
(num, denom)
|
||||
|
||||
| otherwise ->
|
||||
pure $ EBuiltin $ BENumeric $
|
||||
numeric (fromIntegral scale)
|
||||
((num * 10^scale) `div` denom)
|
||||
where
|
||||
r = num % denom
|
||||
upperBound128Bit = 10 ^ (38 :: Integer)
|
||||
|
||||
-- | Convert a rational number into a variable scale Numeric literal. We check that
|
||||
-- the number can be represented at *some* Numeric scale without overflow or
|
||||
-- loss of precision, and then we round and cast (with a multi-scale MUL_NUMERIC)
|
||||
-- to the required scale. This means, for example, that a polymorphic literal like
|
||||
-- "3.141592... : Numeric n" will be correctly rounded for all scales.
|
||||
convertRationalNumericPoly :: Env -> LF.Type -> Integer -> Integer -> ConvertM LF.Expr
|
||||
convertRationalNumericPoly env outputScale num denom =
|
||||
if | max (abs num) (abs denom) >= upperBound128Bit
|
||||
|| inputScale < 0 || inputScale > 37 ->
|
||||
unsupported
|
||||
("Numeric is out of bounds: " ++
|
||||
show ((fromInteger num / fromInteger denom) :: Double) ++
|
||||
". Numeric can only represent 38 digits of precision.")
|
||||
(num, denom)
|
||||
|
||||
| otherwise ->
|
||||
pure $
|
||||
EBuiltin BEMulNumeric
|
||||
`ETyApp` TNat inputScale
|
||||
`ETyApp` TNat 0
|
||||
`ETyApp` outputScale
|
||||
`ETmApp` EBuiltin (BENumeric $ inputNumeric)
|
||||
`ETmApp` EBuiltin (BENumeric $ numeric 0 1)
|
||||
|
||||
where
|
||||
inputNumeric = numericFromRational (num % denom)
|
||||
inputScale = numericScale inputNumeric
|
||||
upperBound128Bit = 10 ^ (38 :: Integer)
|
||||
|
||||
convertModule :: LF.Version -> MS.Map UnitId T.Text -> NormalizedFilePath -> CoreModule -> Either FileDiagnostic LF.Module
|
||||
convertModule lfVersion pkgMap file x = runConvertM (ConversionEnv file Nothing) $ do
|
||||
definitions <- concatMapM (convertBind env) binds
|
||||
@ -624,7 +686,15 @@ convertExpr env0 e = do
|
||||
withTmArg env (varV2, record') args $ \x2 args ->
|
||||
pure (ERecUpd (fromTCon record') (mkField $ fsToText name) x2 x1, args)
|
||||
go env (VarIs "fromRational") (LExpr (VarIs ":%" `App` tyInteger `App` Lit (LitNumber _ top _) `App` Lit (LitNumber _ bot _)) : args)
|
||||
= fmap (, args) $ convertRational env top bot
|
||||
= fmap (, args) $ convertRationalDecimal env top bot
|
||||
go env (VarIs "fromRational") (LType (isNumLitTy -> Just n) : LExpr (VarIs ":%" `App` tyInteger `App` Lit (LitNumber _ top _) `App` Lit (LitNumber _ bot _)) : args)
|
||||
= fmap (, args) $ convertRationalNumericMono env n top bot
|
||||
go env (VarIs "fromRational") (LType scaleTyCoRep : LExpr (VarIs ":%" `App` tyInteger `App` Lit (LitNumber _ top _) `App` Lit (LitNumber _ bot _)) : args)
|
||||
= do
|
||||
scaleType <- convertType env scaleTyCoRep
|
||||
fmap (, args) $ convertRationalNumericPoly env scaleType top bot
|
||||
|
||||
|
||||
go env (VarIs "negate") (tyInt : LExpr (VarIs "$fAdditiveInt") : LExpr (untick -> VarIs "fromInteger" `App` Lit (LitNumber _ x _)) : args)
|
||||
= fmap (, args) $ convertInt64 (negate x)
|
||||
go env (VarIs "fromInteger") (LExpr (Lit (LitNumber _ x _)) : args)
|
||||
@ -1155,6 +1225,7 @@ convertTyCon env t
|
||||
| Just m <- nameModule_maybe (getName t), m == gHC_TYPES =
|
||||
case getOccText t of
|
||||
"Text" -> pure TText
|
||||
"Numeric" -> pure (TBuiltin BTNumeric)
|
||||
"Decimal" ->
|
||||
if envLfVersion env `supports` featureNumeric
|
||||
then pure (TNumeric (TNat 10))
|
||||
@ -1211,6 +1282,8 @@ convertType env t | Just t' <- getTyVar_maybe t
|
||||
= TVar . fst <$> convTypeVar t'
|
||||
convertType env t | Just s <- isStrLitTy t
|
||||
= pure TUnit
|
||||
convertType env t | Just n <- isNumLitTy t, n >= 0
|
||||
= pure (TNat (fromIntegral n))
|
||||
convertType env t | Just (a,b) <- splitAppTy_maybe t
|
||||
= TApp <$> convertType env a <*> convertType env b
|
||||
convertType env x
|
||||
@ -1224,6 +1297,9 @@ convertKind x@(TypeCon t ts)
|
||||
| t == runtimeRepTyCon, null ts = pure KStar
|
||||
-- TODO (drsk): We want to check that the 'Meta' constructor really comes from GHC.Generics.
|
||||
| getOccFS t == "Meta", null ts = pure KStar
|
||||
| Just m <- nameModule_maybe (getName t)
|
||||
, GHC.moduleName m == mkModuleName "GHC.Types"
|
||||
, getOccFS t == "Nat", null ts = pure KNat
|
||||
| t == funTyCon, [_,_,t1,t2] <- ts = KArrow <$> convertKind t1 <*> convertKind t2
|
||||
convertKind (TyVarTy x) = convertKind $ tyVarKind x
|
||||
convertKind x = unhandled "Kind" x
|
||||
|
@ -188,6 +188,37 @@ convertPrim _ "BEToText" (TNumeric10 :-> TText) =
|
||||
convertPrim _ "BEDecimalFromText" (TText :-> TOptional TNumeric10) =
|
||||
ETyApp (EBuiltin BENumericFromText) (TNat 10)
|
||||
|
||||
-- Numeric primitives. These are polymorphic in the scale.
|
||||
convertPrim _ "BEAddNumeric" (TNumeric n1 :-> TNumeric n2 :-> TNumeric n3) | n1 == n2, n1 == n3 =
|
||||
ETyApp (EBuiltin BEAddNumeric) n1
|
||||
convertPrim _ "BESubNumeric" (TNumeric n1 :-> TNumeric n2 :-> TNumeric n3) | n1 == n2, n1 == n3 =
|
||||
ETyApp (EBuiltin BESubNumeric) n1
|
||||
convertPrim _ "BEMulNumeric" (TNumeric n1 :-> TNumeric n2 :-> TNumeric n3) =
|
||||
EBuiltin BEMulNumeric `ETyApp` n1 `ETyApp` n2 `ETyApp` n3
|
||||
convertPrim _ "BEDivNumeric" (TNumeric n1 :-> TNumeric n2 :-> TNumeric n3) =
|
||||
EBuiltin BEDivNumeric `ETyApp` n1 `ETyApp` n2 `ETyApp` n3
|
||||
convertPrim _ "BERoundNumeric" (TInt64 :-> TNumeric n1 :-> TNumeric n2) | n1 == n2 =
|
||||
ETyApp (EBuiltin BERoundNumeric) n1
|
||||
convertPrim _ "BEEqualNumeric" (TNumeric n1 :-> TNumeric n2 :-> TBool) | n1 == n2 =
|
||||
ETyApp (EBuiltin BEEqualNumeric) n1
|
||||
convertPrim _ "BELessNumeric" (TNumeric n1 :-> TNumeric n2 :-> TBool) | n1 == n2 =
|
||||
ETyApp (EBuiltin BELessNumeric) n1
|
||||
convertPrim _ "BELessEqNumeric" (TNumeric n1 :-> TNumeric n2 :-> TBool) | n1 == n2 =
|
||||
ETyApp (EBuiltin BELessEqNumeric) n1
|
||||
convertPrim _ "BEGreaterEqNumeric" (TNumeric n1 :-> TNumeric n2 :-> TBool) | n1 == n2 =
|
||||
ETyApp (EBuiltin BEGreaterEqNumeric) n1
|
||||
convertPrim _ "BEGreaterNumeric" (TNumeric n1 :-> TNumeric n2 :-> TBool) | n1 == n2 =
|
||||
ETyApp (EBuiltin BEGreaterNumeric) n1
|
||||
convertPrim _ "BEInt64ToNumeric" (TInt64 :-> TNumeric n) =
|
||||
ETyApp (EBuiltin BEInt64ToNumeric) n
|
||||
convertPrim _ "BENumericToInt64" (TNumeric n :-> TInt64) =
|
||||
ETyApp (EBuiltin BENumericToInt64) n
|
||||
convertPrim _ "BEToTextNumeric" (TNumeric n :-> TText) =
|
||||
ETyApp (EBuiltin BEToTextNumeric) n
|
||||
convertPrim _ "BENumericFromText" (TText :-> TOptional (TNumeric n)) =
|
||||
ETyApp (EBuiltin BENumericFromText) n
|
||||
|
||||
|
||||
convertPrim _ x ty = error $ "Unknown primitive " ++ show x ++ " at type " ++ renderPretty ty
|
||||
|
||||
-- | Some builtins are only supported in specific versions of DAML-LF.
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
{-# LANGUAGE DamlSyntax #-} -- [DA]
|
||||
|
||||
-- [DA] {-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE CPP #-}
|
||||
{-# LANGUAGE Trustworthy #-}
|
||||
{-# LANGUAGE NoImplicitPrelude, MagicHash, StandaloneDeriving, BangPatterns,
|
||||
KindSignatures, DataKinds, ConstraintKinds,
|
||||
@ -195,8 +195,13 @@ instance Eq Bool where
|
||||
instance Eq Int where
|
||||
(==) = primitive @"BEEqual"
|
||||
|
||||
#ifdef DAML_NUMERIC
|
||||
instance Eq (Numeric n) where
|
||||
(==) = primitive @"BEEqualNumeric"
|
||||
#else
|
||||
instance Eq Decimal where
|
||||
(==) = primitive @"BEEqual"
|
||||
#endif
|
||||
|
||||
instance Eq Text where
|
||||
(==) = primitive @"BEEqual"
|
||||
@ -315,11 +320,19 @@ instance Ord Int where
|
||||
(>=) = primitive @"BEGreaterEq"
|
||||
(>) = primitive @"BEGreater"
|
||||
|
||||
#ifdef DAML_NUMERIC
|
||||
instance Ord (Numeric n) where
|
||||
(<) = primitive @"BELessNumeric"
|
||||
(<=) = primitive @"BELessEqNumeric"
|
||||
(>=) = primitive @"BEGreaterEqNumeric"
|
||||
(>) = primitive @"BEGreaterNumeric"
|
||||
#else
|
||||
instance Ord Decimal where
|
||||
(<) = primitive @"BELess"
|
||||
(<=) = primitive @"BELessEq"
|
||||
(>=) = primitive @"BEGreaterEq"
|
||||
(>) = primitive @"BEGreater"
|
||||
#endif
|
||||
|
||||
instance Ord Text where
|
||||
(<) = primitive @"BELess"
|
||||
|
@ -2,6 +2,7 @@
|
||||
-- SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
{-# LANGUAGE NoImplicitPrelude #-}
|
||||
{-# LANGUAGE CPP #-}
|
||||
daml 1.2
|
||||
|
||||
-- | MOVE Prelude
|
||||
@ -109,14 +110,20 @@ instance Signed Int where
|
||||
signum x = if x == 0 then 0 else if x <= 0 then (-1) else 1
|
||||
abs x = if x <= 0 then negate x else x
|
||||
|
||||
instance Additive Decimal where
|
||||
(+) = primitive @"BEAddDecimal"
|
||||
(-) = primitive @"BESubDecimal"
|
||||
#ifdef DAML_NUMERIC
|
||||
#define IF_NUMERIC(a,b) a
|
||||
#else
|
||||
#define IF_NUMERIC(a,b) b
|
||||
#endif
|
||||
|
||||
instance Additive IF_NUMERIC((Numeric n), Decimal) where
|
||||
(+) = primitive @IF_NUMERIC("BEAddNumeric", "BEAddDecimal")
|
||||
(-) = primitive @IF_NUMERIC("BESubNumeric", "BESubDecimal")
|
||||
negate x = 0.0 - x
|
||||
aunit = 0.0
|
||||
|
||||
instance Multiplicative Decimal where
|
||||
(*) = primitive @"BEMulDecimal"
|
||||
instance Multiplicative IF_NUMERIC((Numeric n), Decimal) where
|
||||
(*) = primitive @IF_NUMERIC("BEMulNumeric", "BEMulDecimal")
|
||||
munit = 1.0
|
||||
x ^ n
|
||||
| n == 0 = 1.0
|
||||
@ -125,10 +132,9 @@ instance Multiplicative Decimal where
|
||||
| n % 2 == 0 = (x ^ (n / 2)) ^ 2
|
||||
| otherwise = x * x ^ (n - 1)
|
||||
|
||||
instance Number Decimal where
|
||||
-- no methods
|
||||
instance Number IF_NUMERIC((Numeric n), Decimal)
|
||||
|
||||
instance Signed Decimal where
|
||||
instance Signed IF_NUMERIC((Numeric n), Decimal) where
|
||||
signum x = if x == 0.0 then 0.0 else if x <= 0.0 then (-1.0) else 1.0
|
||||
abs x = if x <= 0.0 then negate x else x
|
||||
|
||||
@ -143,8 +149,8 @@ class (Multiplicative a) => Divisible a where
|
||||
instance Divisible Int where
|
||||
(/) = primitive @"BEDivInt64"
|
||||
|
||||
instance Divisible Decimal where
|
||||
(/) = primitive @"BEDivDecimal"
|
||||
instance Divisible IF_NUMERIC((Numeric n), Decimal) where
|
||||
(/) = primitive @IF_NUMERIC("BEDivNumeric", "BEDivDecimal")
|
||||
|
||||
-- | Use the `Fractional` class for types that can be divided
|
||||
-- and where the reciprocal is well defined. Instances
|
||||
@ -159,7 +165,7 @@ class (Divisible a) => Fractional a where
|
||||
recip : a -> a
|
||||
recip x = munit / x
|
||||
|
||||
instance Fractional Decimal
|
||||
instance Fractional IF_NUMERIC((Numeric n), Decimal)
|
||||
|
||||
-- | `x % y` calculates the remainder of `x` by `y`
|
||||
(%) : Int -> Int -> Int
|
||||
|
@ -2,6 +2,7 @@
|
||||
-- SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
{-# LANGUAGE NoImplicitPrelude #-}
|
||||
{-# LANGUAGE CPP #-}
|
||||
|
||||
-- GHC desugars Decimal literals to this type
|
||||
daml 1.2
|
||||
@ -15,6 +16,12 @@ data Ratio a = !a :% !a
|
||||
|
||||
type Rational = Ratio Integer
|
||||
|
||||
#ifdef DAML_NUMERIC
|
||||
fromRational : Rational -> Numeric n
|
||||
#else
|
||||
fromRational : Rational -> Decimal
|
||||
#endif
|
||||
|
||||
fromRational = magic @"fromRational"
|
||||
|
||||
{-# NOINLINE fromRational #-}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
{-# LANGUAGE NoImplicitPrelude #-}
|
||||
{-# LANGUAGE MagicHash #-}
|
||||
{-# LANGUAGE CPP #-}
|
||||
|
||||
daml 1.2
|
||||
-- | MOVE Prelude
|
||||
@ -111,8 +112,14 @@ deriving instance (Show a, Show b) => Show (Either a b)
|
||||
|
||||
instance Show Int where
|
||||
show = primitive @"BEToText"
|
||||
|
||||
#ifdef DAML_NUMERIC
|
||||
instance Show (Numeric n) where
|
||||
show = primitive @"BEToTextNumeric"
|
||||
#else
|
||||
instance Show Decimal where
|
||||
show = primitive @"BEToText"
|
||||
#endif
|
||||
|
||||
instance Show Text where
|
||||
show x = "\"" ++ x ++ "\""
|
||||
|
@ -23,6 +23,11 @@ module GHC.Types (
|
||||
Opaque,
|
||||
ifThenElse,
|
||||
primitive, magic,
|
||||
|
||||
#ifdef DAML_NUMERIC
|
||||
Nat, Numeric,
|
||||
#endif
|
||||
|
||||
) where
|
||||
|
||||
import GHC.Prim
|
||||
@ -148,9 +153,26 @@ data Text =
|
||||
-- | HIDE
|
||||
Text Opaque
|
||||
|
||||
#ifdef DAML_NUMERIC
|
||||
|
||||
-- | (Kind) This is the kind of type-level naturals.
|
||||
data Nat
|
||||
|
||||
-- | A type for fixed-point decimal numbers, with the scale
|
||||
-- being passed as part of the type.
|
||||
data Numeric (n:Nat) =
|
||||
-- | HIDE
|
||||
Numeric Opaque
|
||||
|
||||
type Decimal = Numeric 10
|
||||
|
||||
#else
|
||||
|
||||
-- | A type for fixed-point decimals: numbers of the form
|
||||
-- `x / 10e10` where `x` is an integer with `|x| < 10e38`.
|
||||
-- For example, `1.25`.
|
||||
data Decimal =
|
||||
-- | HIDE
|
||||
Decimal Opaque
|
||||
|
||||
#endif
|
||||
|
@ -52,7 +52,7 @@ module DA.Generics (
|
||||
) where
|
||||
|
||||
-- We use some base types
|
||||
import GHC.Types
|
||||
import GHC.Types hiding (Nat)
|
||||
|
||||
-- Needed for instances
|
||||
import GHC.Classes ( Eq(..), Ord(..) )
|
||||
|
@ -2,6 +2,7 @@
|
||||
-- SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
{-# LANGUAGE NoImplicitPrelude #-}
|
||||
{-# LANGUAGE CPP #-}
|
||||
|
||||
daml 1.2
|
||||
-- | MOVE Prelude Our Prelude, extending WiredIn with things that don't need special treatment.
|
||||
@ -23,11 +24,15 @@ import GHC.Real as GHC (fromRational)
|
||||
import GHC.Show as GHC
|
||||
import DA.Types as GHC (Either(..))
|
||||
import GHC.Tuple()
|
||||
import GHC.Types as GHC (Bool (..), Int, Ordering (..), Text, Decimal, ifThenElse, primitive, magic)
|
||||
import GHC.Types as GHC (Bool (..), Int, Ordering (..), Text, Decimal, ifThenElse, primitive, magic
|
||||
#ifdef DAML_NUMERIC
|
||||
, Numeric
|
||||
#endif
|
||||
)
|
||||
|
||||
infixr 0 $
|
||||
-- | Take a function from `a` to `b` and a value of type `a`, and apply the
|
||||
-- function to the value of type `a`, returning a value of type `b`.
|
||||
-- function to the value of type `a`, returning a value of type `b`.
|
||||
-- This function has a very low precedence, which is why you might want to use
|
||||
-- it instead of regular function application.
|
||||
($) : (a -> b) -> a -> b
|
||||
@ -85,7 +90,7 @@ ap : Applicative f => f (a -> b) -> f a -> f b
|
||||
ap = (<*>)
|
||||
|
||||
-- This is a poor doc string but I don't know what the correct improvement would be.
|
||||
-- | Inject a value into the monadic type. For example, for `Update` and a
|
||||
-- | Inject a value into the monadic type. For example, for `Update` and a
|
||||
-- value of type `a`, `return` would give you an `Update a`.
|
||||
return : Applicative m => a -> m a
|
||||
return = pure
|
||||
@ -136,7 +141,7 @@ guard : ActionFail m => Bool -> m ()
|
||||
guard False = fail "guard is false"
|
||||
guard True = pure ()
|
||||
|
||||
-- | This function is a left fold, which you can use to inspect/analyse/consume lists.
|
||||
-- | This function is a left fold, which you can use to inspect/analyse/consume lists.
|
||||
-- `foldl f i xs` performs a left fold over the list `xs` using
|
||||
-- the function `f`, using the starting value `i`.
|
||||
--
|
||||
@ -145,7 +150,7 @@ guard True = pure ()
|
||||
-- ```
|
||||
-- >>> foldl (+) 0 [1,2,3]
|
||||
-- 6
|
||||
--
|
||||
--
|
||||
-- >>> foldl (^) 10 [2,3]
|
||||
-- 1000000
|
||||
-- ```
|
||||
@ -154,8 +159,8 @@ guard True = pure ()
|
||||
foldl : (b -> a -> b) -> b -> [a] -> b
|
||||
foldl = primitive @"BEFoldl"
|
||||
|
||||
-- | `find p xs` finds the first element of the list `xs` where the
|
||||
-- predicate `p` is true. There might not be such an element, which
|
||||
-- | `find p xs` finds the first element of the list `xs` where the
|
||||
-- predicate `p` is true. There might not be such an element, which
|
||||
-- is why this function returns an `Optional a`.
|
||||
find : (a -> Bool) -> [a] -> Optional a
|
||||
find p [] = None
|
||||
@ -507,43 +512,55 @@ fst (x, _) = x
|
||||
snd : (a, b) -> b
|
||||
snd (_, x) = x
|
||||
|
||||
#ifdef DAML_NUMERIC
|
||||
#define IF_NUMERIC(a,b) a
|
||||
#else
|
||||
#define IF_NUMERIC(a,b) b
|
||||
#endif
|
||||
|
||||
-- | `truncate x` rounds `x` toward zero.
|
||||
truncate : Decimal -> Int
|
||||
truncate = primitive @"BEDecimalToInt64"
|
||||
truncate : IF_NUMERIC(Numeric n, Decimal) -> Int
|
||||
truncate = primitive @IF_NUMERIC("BENumericToInt64", "BEDecimalToInt64")
|
||||
|
||||
#ifdef DAML_NUMERIC
|
||||
-- | Convert an `Int` to a `Numeric`.
|
||||
intToNumeric : Int -> Numeric n
|
||||
intToNumeric = primitive @"BEInt64ToNumeric"
|
||||
#endif
|
||||
|
||||
-- | Convert an `Int` to a `Decimal`.
|
||||
intToDecimal : Int -> Decimal
|
||||
intToDecimal = primitive @"BEInt64ToDecimal"
|
||||
intToDecimal = IF_NUMERIC(intToNumeric, primitive @"BEInt64ToDecimal")
|
||||
|
||||
-- | Bankers' Rounding: `roundBankers dp x` rounds `x` to `dp` decimal places, where a `.5` is rounded to the nearest even digit.
|
||||
roundBankers : Int -> Decimal -> Decimal
|
||||
roundBankers = primitive @"BERoundDecimal"
|
||||
roundBankers : Int -> IF_NUMERIC(Numeric n -> Numeric n, Decimal -> Decimal)
|
||||
roundBankers = primitive @IF_NUMERIC("BERoundNumeric", "BERoundDecimal")
|
||||
|
||||
-- | Commercial Rounding: `roundCommercial dp x` rounds `x` to `dp` decimal places, where a `.5` is rounded away from zero.
|
||||
roundCommercial : Int -> Decimal -> Decimal
|
||||
roundCommercial : Int -> IF_NUMERIC(Numeric n -> Numeric n, Decimal -> Decimal)
|
||||
roundCommercial d x =
|
||||
let t = intToDecimal (10 ^ d)
|
||||
let t = IF_NUMERIC(intToNumeric, intToDecimal) (10 ^ d)
|
||||
v = round (x * t)
|
||||
w = intToDecimal v
|
||||
w = IF_NUMERIC(intToNumeric, intToDecimal) v
|
||||
in w / t
|
||||
|
||||
-- | Round a `Decimal` to the nearest integer, where a `.5` is rounded away from zero.
|
||||
round : Decimal -> Int
|
||||
round : IF_NUMERIC(Numeric n, Decimal) -> Int
|
||||
round x = if x > 0.0
|
||||
then truncate (x + 0.5)
|
||||
else truncate (x - 0.5)
|
||||
|
||||
-- | Round a `Decimal` down to the nearest integer.
|
||||
floor : Decimal -> Int
|
||||
floor : IF_NUMERIC(Numeric n, Decimal) -> Int
|
||||
floor x =
|
||||
let i = truncate x
|
||||
in if intToDecimal i <= x then i else i - 1
|
||||
in if IF_NUMERIC(intToNumeric, intToDecimal) i <= x then i else i - 1
|
||||
|
||||
-- | Round a `Decimal` up to the nearest integer.
|
||||
ceiling : Decimal -> Int
|
||||
ceiling : IF_NUMERIC(Numeric n, Decimal) -> Int
|
||||
ceiling x =
|
||||
let i = truncate x
|
||||
in if intToDecimal i < x then i + 1 else i
|
||||
in if IF_NUMERIC(intToNumeric, intToDecimal) i < x then i + 1 else i
|
||||
|
||||
-- | Is the list empty? `null xs` is true if `xs` is the empty list.
|
||||
null : [a] -> Bool
|
||||
|
@ -22,7 +22,7 @@ sumMono z [] = z
|
||||
|
||||
test = scenario do
|
||||
sumInferred 0 [1, 2, 3] === 6
|
||||
sumInferred 0.0 [1.0, 2.0, 3.0] === 6.0
|
||||
sumInferred 0.0 [1.0, 2.0, 3.0] === (6.0 : Decimal)
|
||||
sumPoly 0 [1, 2, 3] === 6
|
||||
sumPoly 0.0 [1.0, 2.0, 3.0] === 6.0
|
||||
sumPoly 0.0 [1.0, 2.0, 3.0] === (6.0 : Decimal)
|
||||
sumMono 0 [1, 2, 3] === 6
|
||||
|
@ -197,7 +197,7 @@ testIsInfixOf = scenario do
|
||||
|
||||
testMapAccumL = scenario do
|
||||
(6, [0,1,3]) === mapAccumL (\a x -> (a+x, a)) 0 [1, 2, 3]
|
||||
(7.1, [1,3,7]) === mapAccumL (\a x -> (a + x, floor (a + x))) 0.0 [1.2, 2.5, 3.4]
|
||||
(7.1, [1,3,7]) === mapAccumL (\a x -> (a + x, floor (a + x))) 0.0 ([1.2, 2.5, 3.4] : [Decimal])
|
||||
(42, []) === mapAccumL (\a x -> (a*x, a)) 42 []
|
||||
|
||||
testIntersperse = scenario do
|
||||
@ -295,12 +295,12 @@ testInit = scenario do
|
||||
submitMustFail p $ pure $ init []
|
||||
|
||||
testFoldl1 = scenario do
|
||||
1.25 === foldl1 (/) [10.0, 2.0, 4.0]
|
||||
1.25 === foldl1 (/) ([10.0, 2.0, 4.0] : [Decimal])
|
||||
"abc" === foldl1 (<>) ["a", "b", "c"]
|
||||
-4 === foldl1 (-) [1, 2, 3]
|
||||
|
||||
testFoldr1 = scenario do
|
||||
3.0 === foldr1 (/) [9.0, 150.0, 50.0]
|
||||
3.0 === foldr1 (/) ([9.0, 150.0, 50.0] : [Decimal])
|
||||
"abc" === foldr1 (<>) ["a", "b", "c"]
|
||||
2 === foldr1 (-) [1, 2, 3]
|
||||
|
||||
@ -334,14 +334,14 @@ testFindIndex = scenario do
|
||||
testSum = scenario do
|
||||
assert $ sum [1, 2, 3] == 6
|
||||
assert $ sum [] == 0
|
||||
assert $ sum [] == 0.0
|
||||
assert $ sum [40.0, 2.0] == 42.0
|
||||
assert $ sum [] == (0.0 : Decimal)
|
||||
assert $ sum [40.0, 2.0] == (42.0 : Decimal)
|
||||
|
||||
testProduct = scenario do
|
||||
assert $ product [1, 2, 3] == 6
|
||||
assert $ product [] == 1
|
||||
assert $ product [] == 1.0
|
||||
assert $ product [21.0, 2.0] == 42.0
|
||||
assert $ product [] == (1.0 : Decimal)
|
||||
assert $ product [21.0, 2.0] == (42.0 : Decimal)
|
||||
|
||||
testDelete = scenario do
|
||||
delete "a" ["b","a","n","a","n","a"] === ["b","n","a","n","a"]
|
||||
|
@ -8,5 +8,5 @@ main = scenario do
|
||||
alice <- getParty "alice"
|
||||
submit alice do
|
||||
assert $ [1] == [1]
|
||||
assert $ [1.0] /= [2.0]
|
||||
assert $ [1.0] /= ([2.0] : [Decimal])
|
||||
assert $ [""] /= []
|
||||
|
@ -14,7 +14,7 @@ testEmpty = scenario do
|
||||
|
||||
testSize = scenario do
|
||||
0 === size (fromList ([] : [(Int, Decimal)]))
|
||||
3 === size (fromList [(1, 2.0), (2, 9.0), (3, 2.2)])
|
||||
3 === size (fromList ([(1, 2.0), (2, 9.0), (3, 2.2)] : [(Int, Decimal)]))
|
||||
|
||||
testToList = scenario do
|
||||
[(1, "c"), (2, "a"), (5, "b")] === toList (fromList [(2, "a"), (5, "b"), (1, "c")])
|
||||
@ -29,13 +29,13 @@ testFromListWith = scenario do
|
||||
fromListWith (<>) [] === (M.empty : Map Int Text)
|
||||
|
||||
testMember = scenario do
|
||||
False === member "a" (fromList [("", 1.0), ("b", 2.0), ("c", 3.0)])
|
||||
True === member "" (fromList [("", 1.0), ("b", 2.0), ("c", 3.0)])
|
||||
False === member "a" (fromList ([("", 1.0), ("b", 2.0), ("c", 3.0)] : [(Text, Decimal)]))
|
||||
True === member "" (fromList ([("", 1.0), ("b", 2.0), ("c", 3.0)] : [(Text, Decimal)]))
|
||||
False === member 2 (fromList [])
|
||||
|
||||
testLookup = scenario do
|
||||
None === M.lookup "a" (fromList [("", 1.0), ("b", 2.0), ("c", 3.0)])
|
||||
Some 1.0 === M.lookup "" (fromList [("", 1.0), ("b", 2.0), ("c", 3.0)])
|
||||
None === M.lookup "a" (fromList ([("", 1.0), ("b", 2.0), ("c", 3.0)] : [(Text, Decimal)]))
|
||||
Some 1.0 === M.lookup "" (fromList ([("", 1.0), ("b", 2.0), ("c", 3.0)] : [(Text, Decimal)]))
|
||||
None === M.lookup 2 (fromList ([] : [(Int, Text)]))
|
||||
|
||||
testNull = scenario do
|
||||
|
@ -48,7 +48,7 @@ testOptionalToList = scenario do
|
||||
|
||||
testFromOptional = scenario do
|
||||
1 === fromOptional 0 (Some 1)
|
||||
2.3 === fromOptional 2.3 None
|
||||
(2.3 : Decimal) === fromOptional 2.3 None
|
||||
|
||||
testIsSome = scenario do
|
||||
True === isSome (Some "a")
|
||||
|
@ -30,15 +30,15 @@ testRemainder = scenario do
|
||||
testId = scenario do
|
||||
1 === identity 1
|
||||
"abc" === identity "abc"
|
||||
[1.0, 2.0, 3.0] === identity [1.0, 2.0, 3.0]
|
||||
[1.0, 2.0, 3.0] === identity ([1.0, 2.0, 3.0] : [Decimal])
|
||||
|
||||
testFoldl = scenario do
|
||||
2.5 === foldl (/) 150.0 [5.0, 4.0, 3.0]
|
||||
2.5 === foldl (/) 150.0 ([5.0, 4.0, 3.0] : [Decimal])
|
||||
"abc" === foldl (<>) "" ["a", "b", "c"]
|
||||
-6 === foldl (-) 0 [1, 2, 3]
|
||||
|
||||
testFoldr = scenario do
|
||||
6.0 === foldr (/) 3.0 [36.0, 300.0, 150.0]
|
||||
6.0 === foldr (/) 3.0 ([36.0, 300.0, 150.0] : [Decimal])
|
||||
"abc" === foldr (<>) "" ["a", "b", "c"]
|
||||
[1, 2, 3] === foldr (::) [] [1, 2, 3]
|
||||
2 === foldr (-) 0 [1, 2, 3]
|
||||
@ -86,12 +86,12 @@ testAnd = scenario do
|
||||
True === and [True, True]
|
||||
|
||||
testElem = scenario do
|
||||
True === elem 1.0 [1.0, 2.0, 3.0]
|
||||
True === elem 1.0 ([1.0, 2.0, 3.0] : [Decimal])
|
||||
False === elem 4 [1, 2, 3]
|
||||
False === elem "" []
|
||||
|
||||
testNotElem = scenario do
|
||||
False === notElem 1.0 [1.0, 2.0, 3.0]
|
||||
False === notElem 1.0 ([1.0, 2.0, 3.0] : [Decimal])
|
||||
True === notElem 4 [1, 2, 3]
|
||||
True === notElem "" []
|
||||
|
||||
@ -124,8 +124,8 @@ testOptional = scenario do
|
||||
5 === optional 5 T.length (Some "12345")
|
||||
|
||||
testEither = scenario do
|
||||
11 === either (+1) floor (Left 10)
|
||||
11 === either (+1) floor (Right 11.5)
|
||||
11 === either (+1) (floor : Decimal -> Int) (Left 10)
|
||||
11 === either (+1) (floor : Decimal -> Int) (Right 11.5)
|
||||
|
||||
testAppend = scenario do
|
||||
"abc123" === "abc" <> "123"
|
||||
@ -168,9 +168,9 @@ testSequence = scenario do
|
||||
Right [1, 2] === sequence [Right 1, Right 2 : Either Text Int]
|
||||
|
||||
testRbind = scenario do
|
||||
Some 1 === (Some . floor =<< Some 1.9)
|
||||
None === (Some . floor =<< None)
|
||||
(None : Optional Int) === (const None =<< Some 1.9)
|
||||
Some 1 === (Some . floor =<< Some (1.9 : Decimal))
|
||||
None === (Some . (floor : Decimal -> Int) =<< None)
|
||||
(None : Optional Int) === (const None =<< Some (1.9 : Decimal))
|
||||
|
||||
testConcatMap = scenario do
|
||||
["a", "b", "c", "d"] === concatMap T.explode ["a", "bcd"]
|
||||
@ -239,20 +239,20 @@ testZip3 = scenario do
|
||||
[] === zip3 ([] : [Int]) ([] : [Text]) ([] : [Decimal])
|
||||
[] === zip3 [1, 2, 3] ([] : [Text]) ([] : [Decimal])
|
||||
[] === zip3 ([] : [Int]) ["A", "B", "C"] ([] : [Decimal])
|
||||
[] === zip3 ([] : [Int]) ([] : [Text]) [1.0, 2.0]
|
||||
[(1, "A", 2.0), (2, "B", 1.0)] === zip3 [1, 2, 3] ["A", "B"] [2.0, 1.0, 3.0]
|
||||
[(1, "A", 2.0), (2, "B", 1.0)] === zip3 [1, 2] ["A", "B", "C", "D"] [2.0, 1.0, 3.0]
|
||||
[(1, "A", 2.0), (2, "B", 1.0), (0, "C", 3.0)] === zip3 [1, 2, 0, 5] ["A", "B", "C", "D"] [2.0, 1.0, 3.0]
|
||||
[] === zip3 ([] : [Int]) ([] : [Text]) ([1.0, 2.0] : [Decimal])
|
||||
[(1, "A", 2.0), (2, "B", 1.0)] === zip3 [1, 2, 3] ["A", "B"] ([2.0, 1.0, 3.0] : [Decimal])
|
||||
[(1, "A", 2.0), (2, "B", 1.0)] === zip3 [1, 2] ["A", "B", "C", "D"] ([2.0, 1.0, 3.0] : [Decimal])
|
||||
[(1, "A", 2.0), (2, "B", 1.0), (0, "C", 3.0)] === zip3 [1, 2, 0, 5] ["A", "B", "C", "D"] ([2.0, 1.0, 3.0] : [Decimal])
|
||||
|
||||
testZipWith = scenario do
|
||||
[(1, "A"), (2, "B")] === zipWith (,) [1, 2] ["A", "B", "C", "D"]
|
||||
[(1, "A"), (2, "B"), (0, "C")] === zipWith (,) [1, 2, 0, 4, 9] ["A", "B", "C"]
|
||||
[11, 25, 33] === zipWith ((+) . floor) [1.9, 5.4, 3.2] [10, 20, 30, 40]
|
||||
[11, 25, 33] === zipWith ((+) . floor) ([1.9, 5.4, 3.2] : [Decimal]) [10, 20, 30, 40]
|
||||
|
||||
testZipWith3 = scenario do
|
||||
[(1, "A", 2.2), (2, "B", 1.1)] === zipWith3 (,,) [1, 2] ["A", "B", "C", "D"] [2.2, 1.1, 3.3]
|
||||
[(1, "A", 2.2), (2, "B", 1.1), (0, "C", 3.3)] === zipWith3 (,,) [1, 2, 0, 4, 9] ["A", "B", "C"] [2.2, 1.1, 3.3]
|
||||
[11, 21, 31] === zipWith3 (\x y z -> floor x + y - T.length z) [1.9, 5.4, 3.2] [10, 20, 30, 40] ["", "....", ".."]
|
||||
[(1, "A", 2.2), (2, "B", 1.1)] === zipWith3 (,,) [1, 2] ["A", "B", "C", "D"] ([2.2, 1.1, 3.3] : [Decimal])
|
||||
[(1, "A", 2.2), (2, "B", 1.1), (0, "C", 3.3)] === zipWith3 (,,) [1, 2, 0, 4, 9] ["A", "B", "C"] ([2.2, 1.1, 3.3] : [Decimal])
|
||||
[11, 21, 31] === zipWith3 (\x y z -> floor x + y - T.length z) ([1.9, 5.4, 3.2] : [Decimal]) [10, 20, 30, 40] ["", "....", ".."]
|
||||
|
||||
testUnzip = scenario do
|
||||
([], []) === unzip ([] : [(Int, Text)])
|
||||
@ -260,7 +260,7 @@ testUnzip = scenario do
|
||||
|
||||
testUnzip3 = scenario do
|
||||
([], [], []) === unzip3 ([] : [(Int, Text, Decimal)])
|
||||
([1, 2, 3], ["A", "B", "C"], [2.0, 1.0, 9.0]) === unzip3 [(1, "A", 2.0), (2, "B", 1.0), (3, "C", 9.0)]
|
||||
([1, 2, 3], ["A", "B", "C"], [2.0, 1.0, 9.0]) === unzip3 [(1, "A", 2.0), (2, "B", 1.0), (3, "C", (9.0 : Decimal))]
|
||||
|
||||
testFst = scenario do
|
||||
1 === fst (1, "A")
|
||||
@ -285,32 +285,32 @@ testIntToDecimal = scenario do
|
||||
assert $ intToDecimal 0 == 0.0
|
||||
|
||||
testTruncate = scenario do
|
||||
assert $ truncate 14.9 == 14
|
||||
assert $ truncate 15.0 == 15
|
||||
assert $ truncate (-9.3) == (-9)
|
||||
assert $ truncate 0.0 == 0
|
||||
assert $ truncate (14.9 : Decimal) == 14
|
||||
assert $ truncate (15.0 : Decimal) == 15
|
||||
assert $ truncate ((-9.3) : Decimal) == (-9)
|
||||
assert $ truncate (0.0 : Decimal) == 0
|
||||
|
||||
testCeiling = scenario do
|
||||
assert $ ceiling 14.9 == 15
|
||||
assert $ ceiling 15.0 == 15
|
||||
assert $ ceiling (-9.3) == (-9)
|
||||
assert $ ceiling 0.0 == 0
|
||||
assert $ ceiling (14.9 : Decimal) == 15
|
||||
assert $ ceiling (15.0 : Decimal) == 15
|
||||
assert $ ceiling ((-9.3) : Decimal) == (-9)
|
||||
assert $ ceiling (0.0 : Decimal) == 0
|
||||
|
||||
testFloor = scenario do
|
||||
assert $ floor 14.9 == 14
|
||||
assert $ floor 15.0 == 15
|
||||
assert $ floor (-9.3) == (-10)
|
||||
assert $ floor 0.0 == 0
|
||||
assert $ floor (14.9 : Decimal) == 14
|
||||
assert $ floor (15.0 : Decimal) == 15
|
||||
assert $ floor ((-9.3) : Decimal) == (-10)
|
||||
assert $ floor (0.0 : Decimal) == 0
|
||||
|
||||
testRound = scenario do
|
||||
assert $ roundCommercial 0 10.5 == 11.0
|
||||
assert $ roundCommercial 2 22.105 == 22.110
|
||||
assert $ roundBankers 0 10.5 == 10.0
|
||||
assert $ roundBankers 2 22.105 == 22.100
|
||||
assert $ roundCommercial 0 (-10.5) == -11.0
|
||||
assert $ roundCommercial 2 (-22.105) == -22.110
|
||||
assert $ roundBankers 0 (-10.5) == -10.0
|
||||
assert $ roundBankers 2 (-22.105) == -22.100
|
||||
assert $ roundCommercial 0 10.5 == (11.0 : Decimal)
|
||||
assert $ roundCommercial 2 22.105 == (22.110 : Decimal)
|
||||
assert $ roundBankers 0 10.5 == (10.0 : Decimal)
|
||||
assert $ roundBankers 2 22.105 == (22.100 : Decimal)
|
||||
assert $ roundCommercial 0 (-10.5) == (-11.0 : Decimal)
|
||||
assert $ roundCommercial 2 (-22.105) == (-22.110 : Decimal)
|
||||
assert $ roundBankers 0 (-10.5) == (-10.0 : Decimal)
|
||||
assert $ roundBankers 2 (-22.105) == (-22.100 : Decimal)
|
||||
|
||||
testNth = scenario do
|
||||
let l = [1, 5, 10]
|
||||
@ -318,12 +318,12 @@ testNth = scenario do
|
||||
assert $ v == 5
|
||||
|
||||
testDiv = scenario do
|
||||
assert $ 10.0 / 2.0 == 5.0
|
||||
assert $ 13.2 / 5.0 == 2.64
|
||||
assert $ 10.0 / 2.0 == (5.0 : Decimal)
|
||||
assert $ 13.2 / 5.0 == (2.64 : Decimal)
|
||||
|
||||
assert $ 0.5 == recip 2.0
|
||||
1.0 / 3.0 === 0.3333333333
|
||||
1.0 / 3.0 * 3.0 === 0.9999999999
|
||||
assert $ 0.5 == recip (2.0 : Decimal)
|
||||
1.0 / 3.0 === (0.3333333333 : Decimal)
|
||||
1.0 / 3.0 * 3.0 === (0.9999999999 : Decimal)
|
||||
|
||||
10 / 2 === 5
|
||||
10 / 3 === 3
|
||||
|
@ -9,4 +9,4 @@ daml 1.2
|
||||
module RationalLowerBoundError where
|
||||
|
||||
-- -10^38 / 10^10
|
||||
a = -10000000000000000000000000000.0000000000
|
||||
a = (-10000000000000000000000000000.0000000000 : Decimal)
|
||||
|
@ -8,4 +8,4 @@ daml 1.2
|
||||
module RationalLowerBoundMax where
|
||||
|
||||
-- -10^38 + 1 / 10^10
|
||||
a = -9999999999999999999999999999.9999999999
|
||||
a = (-9999999999999999999999999999.9999999999 : Decimal)
|
||||
|
@ -7,4 +7,4 @@ daml 1.2
|
||||
|
||||
module RationalPrecisionMax where
|
||||
|
||||
a = 0.0000000005
|
||||
a = (0.0000000005 : Decimal)
|
||||
|
@ -8,4 +8,4 @@ daml 1.2
|
||||
|
||||
module RationalPrecisionUpperBoundError where
|
||||
|
||||
a = 0.00000000005
|
||||
a = (0.00000000005 : Decimal)
|
||||
|
@ -9,4 +9,4 @@ daml 1.2
|
||||
module RationalUpperBound where
|
||||
|
||||
-- 10^38 / 10^10
|
||||
a = 10000000000000000000000000000.0000000000
|
||||
a = (10000000000000000000000000000.0000000000 : Decimal)
|
||||
|
@ -30,8 +30,8 @@ main = scenario do
|
||||
show (Field1 Bar (Some Blue) : Fields Int) === "Field1 {foo = bar, color = Some Blue}"
|
||||
show (Some (Some Red)) === "Some (Some Red)"
|
||||
show 1 === "1"
|
||||
show 1.0 === "1.0"
|
||||
show 1.1 === "1.1"
|
||||
show (1.0 : Decimal) === "1.0"
|
||||
show (1.1 : Decimal) === "1.1"
|
||||
show "test" === "\"test\""
|
||||
show True === "True"
|
||||
show False === "False"
|
||||
|
@ -14,7 +14,7 @@ testEmpty = scenario do
|
||||
|
||||
testSize = scenario do
|
||||
0 === size (fromList ([] : [(Text, Decimal)]))
|
||||
3 === size (fromList [("1", 2.0), ("2", 9.0), ("3", 2.2)])
|
||||
3 === size (fromList ([("1", 2.0), ("2", 9.0), ("3", 2.2)] : [(Text, Decimal)]))
|
||||
|
||||
testToList = scenario do
|
||||
[("1", "c"), ("2", "a"), ("5", "b")] === toList (fromList [("2", "a"), ("5", "b"), ("1", "c")])
|
||||
@ -29,13 +29,13 @@ testFromListWith = scenario do
|
||||
fromListWith (++) [] === (empty : TextMap [Int])
|
||||
|
||||
testMember = scenario do
|
||||
False === member "a" (fromList [("", 1.0), ("b", 2.0), ("c", 3.0)])
|
||||
True === member "" (fromList [("", 1.0), ("b", 2.0), ("c", 3.0)])
|
||||
False === member "a" (fromList ([("", 1.0), ("b", 2.0), ("c", 3.0)] : [(Text, Decimal)]))
|
||||
True === member "" (fromList ([("", 1.0), ("b", 2.0), ("c", 3.0)] : [(Text, Decimal)]))
|
||||
False === member "2" (fromList [])
|
||||
|
||||
testLookup = scenario do
|
||||
None === TM.lookup "a" (fromList [("", 1.0), ("b", 2.0), ("c", 3.0)])
|
||||
Some 1.0 === TM.lookup "" (fromList [("", 1.0), ("b", 2.0), ("c", 3.0)])
|
||||
None === TM.lookup "a" (fromList ([("", 1.0), ("b", 2.0), ("c", 3.0)] : [(Text, Decimal)]))
|
||||
Some 1.0 === TM.lookup "" (fromList ([("", 1.0), ("b", 2.0), ("c", 3.0)] : [(Text, Decimal)]))
|
||||
None === TM.lookup "2" (fromList ([] : [(Text, Text)]))
|
||||
|
||||
testNull = scenario do
|
||||
|
@ -12,8 +12,8 @@ testFirst = scenario do
|
||||
(3, "abc") === first length ([1,2,3], "abc")
|
||||
|
||||
testSecond = scenario do
|
||||
(5.0, 12) === second (*4) (5.0, 3)
|
||||
(5.0, 3) === second length (5.0, [1,2,3])
|
||||
(5.0, 12) === second (*4) ((5.0 : Decimal), 3)
|
||||
(5.0, 3) === second length ((5.0 : Decimal), [1,2,3])
|
||||
|
||||
testBoth = scenario do
|
||||
(3, 1) === both length ([1,2,3], [1])
|
||||
|
@ -42,7 +42,7 @@ private[validation] object Typing {
|
||||
protected[validation] lazy val typeOfBuiltinFunction = {
|
||||
val alpha = TVar(Name.assertFromString("$alpha$"))
|
||||
val beta = TVar(Name.assertFromString("$beta$"))
|
||||
val gamma = TVar(Name.assertFromString("$beta$"))
|
||||
val gamma = TVar(Name.assertFromString("$gamma$"))
|
||||
def tBinop(typ: Type): Type = typ ->: typ ->: typ
|
||||
val tNumBinop = TForall(alpha.name -> KNat, tBinop(TNumeric(alpha)))
|
||||
val tMultiNumBinop =
|
||||
|
Loading…
Reference in New Issue
Block a user