Cirdec's answer to a largely unrelated question made me wonder how best to represent natural numbers with constant-time addition, subtraction by one, and testing for zero.
Suppose we use
data Nat = Z | S Nat
Then we can write
Z + n = n S m + n = S(m+n)
We can calculate m+n
in O(1) time by placing m-r
debits (for some constant r
), one on each S
constructor added onto n
. To get O(1) isZero
, we need to be sure to have at most p
debits per S
constructor, for some constant p
. This works great if we calculate a + (b + (c+...))
, but it falls apart if we calculate ((...+b)+c)+d
. The trouble is that the debits stack up on the front end.
The easy way out is to just use catenable lists, such as the ones Okasaki describes, directly. There are two problems:
O(n) space is not really ideal.
It's not entirely clear (at least to me) that the complexity of bootstrapped queues is necessary when we don't care about order the way we would for lists.
The set of natural numbers, denoted N, can be defined in either of two ways: N = {0, 1, 2, 3, ...} In mathematical equations, unknown or unspecified natural numbers are represented by lowercase, italicized letters from the middle of the alphabet. The most common is n, followed by m, p, and q.
The principle of induction provides a recipe for proving that every natural number has a certain property: to show that P holds of every natural number, show that it holds of 0, and show that whenever it holds of some number n, it holds of n+1. This form of proof is called a proof by induction.
Hence, 1729 natural numbers are there with the property that they can be expressed as the sum of the cubes of two natural numbers. Problem fixing, repair, tuning, and knowledge acquisition can all be done by trial and error. The procedure is known as generate and test in the field of computer science (Brute force).
The natural numbers from 1 to 100 are 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, ...
As far as I know, Idris (a dependently-typed purely functional language which is very close to Haskell) deals with this in a quite straightforward way. Compiler is aware of Nat
s and Fin
s (upper-bounded Nat
s) and replaces them with machine integer types and operations whenever possible, so the resulting code is pretty effective. However, that's not true for custom types (even isomorphic ones) as well as for compilation stage (there were some code samples using Nat
s for type checking which resulted in exponential growth in compile-time, I can provide them if needed).
In case of Haskell, I think a similar compiler extension may be implemented. Another possibility is to make TH macros which would transform the code. Of course, both of options aren't easy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With