How does the REPL handle floats, and how can you perform Mathematical functions on them?

Thanks for that write-up, I like experimenting with REPLs, all types.

It took me a bit to discover some helpful features, and I was able to write some simple Physics formulae using fake information.

However I note this:

daml> let X = 20
daml> let y = 5
daml> let q = 10
daml> let z = (x*y)/q
daml> z
10

However if I assign a variable to a Float, there are issues:

daml> let w = 26.0
parse error on input ‘=’
daml> let w = "26.0"
26.0
daml> w
"26.0"

If I try a simple equation using a Float, the REPL throws errors.

As a Haskell/DAML novice, how does the REPL handle floats, and how can you perform Mathematical functions on them? Does this require the import of a specific Module/Library?

2 Likes

The Daml language simply des not have floating point numbers. This is a design choice.

If you still want decimal numbers, you can have them with the Numeric type, which is a family of fixed-point decimal number types. The Decimal type is the member of that family with 10 decimal places. Here is an example:

$ daml repl
daml> let w = 26.0 : Decimal
daml> w + 1.0
27.0
daml> w + 0.5
26.5
daml> w + 0.0000000000000000005
File:     Line3.daml
Hidden:   no
Range:    6:1-6:5
Source:   Core to DAML-LF
Severity: DsError
Message: 
  Failure to process DAML program, this feature is not currently supported.
  Rational is out of bounds: 5.0e-19. It cannot be represented without loss of precision. Maximum
  precision for the Numeric 10 type is 10^-10.
  (1, 2000000000000000000)
daml> let x = 1.0 : Numeric 2
daml> x + w
File:     Line4.daml
Hidden:   no
Range:    7:21-7:22
Source:   typecheck
Severity: DsError
Message: 
  Line4.daml:7:21: error:
  • Couldn't match type ‘10’ with ‘2’
  Expected type: Numeric 2
  Actual type: Decimal
  • In the second argument of ‘(+)’, namely ‘w’
  In the first argument of ‘show’, namely ‘(x + w)’
  In the first argument of ‘return’, namely ‘(show (x + w))’
daml> 

You have to specify the type of decimal numbers because you have to specify their scale. Decimal numbers need to have to same scale to operate on them.

2 Likes

I think it’s also worth pointing out that

let w = 26.0

does not produce a parse error, it produces a type error because it cannot infer the scale of the Numeric:

daml> let x = 26.0
File:     Line1.daml
Hidden:   no
Range:    7:14-7:18
Source:   typecheck
Severity: DsError
Message: 
  Line1.daml:7:14: error:
  • Ambiguous type variable ‘n0’ arising from the literal ‘26.0’
  prevents the constraint ‘(NumericScale n0)’ from being solved.
  Relevant bindings include
  x : Numeric n0 (bound at Line1.daml:7:10)
  expr : Int -> Script (Numeric n0) (bound at Line1.daml:6:1)
  Probable fix: use a type annotation to specify what ‘n0’ should be.
  These potential instances exist:
  instance NumericScale 0 -- Defined in ‘GHC.Classes’
  instance NumericScale 1 -- Defined in ‘GHC.Classes’
  instance NumericScale 10 -- Defined in ‘GHC.Classes’
  ...plus 35 others
  (use -fprint-potential-instances to see them all)
  • In the expression: 26.0
  In an equation for ‘x’: x = 26.0
  In the expression:
  do let x = 26.0
  return x
3 Likes

Thank you for the reply, I will do some experimenting and reading.

That solution makes sense but it sure looks a little ‘clunky’ :grinning:

To give a bit more background on this, using floating point numbers can cause unexpected and dangerous errors, especially in the type of software which Daml is commonly used for.

Here are a few links which explain this much better than I can:

  1. Why You Should Never Use Float and Double for Monetary Calculations - DZone Java
  2. floating point - Why not use Double or Float to represent currency? - Stack Overflow
2 Likes

Thank you for the extra information, I will read more on this.

1 Like

There is a lot to say about floating point arithmetics and all the ways it can go wrong, and all the tricks and techniques you can use to still make it produce “close enough” results.

I find the simplest way to convince yourself they should not be used when counting money is to just do 0.1 + 0.2 in your favourite language.

Here’s a line of Javascript I just executed in my browser console:

> 0.1 + 0.2 == 0.3
< false

Though, of course:

$ daml repl
> 0.1 + 0.2 == (0.3 : Decimal)
True
>
2 Likes

It is the same using the REPL from Python3 … I am convinced :grinning:

1 Like