Bend/docs/native-numbers.md
2024-04-03 20:47:47 +02:00

1.9 KiB

Native numbers

HVM is more than a pure functional programming language. HVM also supports native unsigned 60-bits integers to improve performance.

two = 2

Native integers should be used instead of Scott-encoded natural numbers when performance is needed.

Numbers can also be written in binary or hexadecimal form. Underscores can be optionally used as digit separators to make large numbers more readable.

decimal =     1194684
binary =      0b100_100_011_101_010_111_100
hexadecimal = 0x123_abc

There is also support for native operations. They are written in reverse polish notation and take 2 arguments each.

some_val = (+ (+ 7 4) (* 2 3))

The current operations include +, -, *, /, %, ==, !=, <, >, <=, >=, &, |, ^, ~, <<, >>.

The ~ symbol stands for NOT. It takes two arguments and calculates the 60-bit binary NOT of the first one, but ignores its second one. However, because of implementation details, the second argument must be a number too.

main = (~ 42 10)
// Outputs the same thing as (~ 42 50)
// And as (~ 42 1729)
// But not the same thing as (~ 42 *) (!)

HVM-lang also includes a switch syntax for pattern-matching native numbers. The 0 case is chosen when n is 0, and the _ case is chosen when n is greater than 0. The previous number, by default, bound to n-1.

Number.to_church = λn λf λx
  switch n {
    0: x
    _: (f (Number.to_church n-1 f x))
  }

Using everything we learned, we can write a program that calculates the n-th Fibonacci number using native numbers

fibonacci = λn // n is the argument
  switch n {
    // If the number is 0, then return 0
    0: 0
    // If the number is 1, then return 1
    1: 1
    // Otherwise, return the sum of (fib (n-2 + 1)) and (fib n-2)
    // The successor pattern provides a `var`-`successor number` bind
    _: (+ (fibonacci (+ n-2 1)) (fibonacci n-2))
  }

main = (fibonacci 15)