How to use generic numeric types with real mathematic values

G-d willing

Hello,
I would like to write a function that gets a generic numeric value, and according to its value, it will return a specific text message.

doSomething : (Additive a, Eq a, IsNumeric a) => a -> Text
doSomething x = 
  case x of
    0 -> "This is zero"
    _ -> "Non zero number"

However, daml cannot compile it because:

error:
    • Couldn't match expected type ‘a’ with actual type ‘Int’
      ‘a’ is a rigid type variable bound by
        the type signature for:
          doSomething : forall a.
                        (Additive a, Eq a, IsNumeric a) =>
                        a -> Text

I understand the problem I am having, but what is the way to resolve this?
Is there some kind of generic representation for numbers in Daml?

Hi @cohen.avraham,

I’m not sure about the details here — it looks like the Daml compiler does not infer the type of the literal 0, but instead assumes it’s an Int. Perhaps someone from the compiler team can shed more light on how to get generic literals, or why that’s not supported in Daml.

I suspect the design intent is that, in Daml, which, remember, is a language designed for recording things on a ledger, not a truly general purpose programming language, we expect to know which types of numbers we’re working with, because that’s going to be necessary to interact with the API properly.

For this specific example, you can get it to work using the Additive typeclass and its unit, which is zero for numbers:

doSomething : (Additive a, Eq a) => a -> Text
doSomething x = if x == aunit
  then "This is zero"
  else "Non zero number"

Depending on your real use-case, there may or may not be a similar way to achieve it.

Thank you @Gary_Verhaegen for your answer, but how can I use it for values other than zero?
Let’s do the following function:

translateNumber : (Eq a, IsNumeric a) => a -> Text
translateNumber x =
  case x of
    aunit -> "Zero number"
    1 -> "One"
    2 -> "Two"
    _ -> "Rest"

Now I am getting the error on the 1 , 2 as well.

As I said, I don’t think Daml is set up for that kind of genericity. Concretely, I believe the Number typeclass lacks a conversion function, along the lines of Haskell’s fromIntegral et al.

In this specifica case, you can still sort of cheat your way out of it by relying on the unit for multiplication, with something like:

translateNumber : (Eq a, Additive a, Multiplicative a) => a -> Text
translateNumber n =
  let zero = aunit
      one = munit
      two = one + one
      three = two + one
      four = two * two
      eleven = two * two + three
  in
  if n == zero
  then "Zero"
  else if n == one
  then "One"
  else if n == two
  then "Two"
  else if n == three
  then "Three"
  else if n == four
  then "Four"
  else if n == eleven
  then "Eleven"
  else "Unknown number"

But, basically, as far as I can tell, you have to manage to write it without using any literal number, which also means you can’t use pattern matching.

This is far from my area of expertise, so it’s entirely possible I’m missing something here.

2 Likes

I genuinely appreciate your help in the solution. I hoped to get a more generic solution, I wish Daml had that kind of auto-conversion process for numeric types. It could be beneficial.
Having said that, you offered a solution that works, it’s better than nothing. Thanks.

1 Like

It looks like I may have misinterpreted your request - if you’re only interested in genericity over Numeric n types (i.e. across different values of n), but don’t require Int, you can use the fromNumeric method of the IsNumeric class:

translateNumeric : NumericScale a => Numeric a -> Text
translateNumeric n
  | n == fromNumeric (0.0 : Decimal) = "zero"
  | n == fromNumeric (3.141592654 : Decimal) = "pi, or close enough"
  | n == fromNumeric (4.0 : Decimal) = "four"
  | n == fromNumeric (11.0 : Decimal) = "eleven"
  | n == fromNumeric (42.0 : Decimal) = "the answer"
  | n == fromNumeric (100.0 : Decimal) = "a hundred"
  | otherwise = "just another number :" <> show n

Hi @Gary_Verhaegen , no you didn’t misinterpret my question.
I am aware of the fromNumeric function