Skip to content

Instantly share code, notes, and snippets.

@hez2010
Last active August 12, 2021 04:31
Show Gist options
  • Save hez2010/39af351442c1b71a46e194bca72abfde to your computer and use it in GitHub Desktop.
Save hez2010/39af351442c1b71a46e194bca72abfde to your computer and use it in GitHub Desktop.
Peano's Natural using C# 10
var a = Nat.FromNumber(5);
a++; a++; a++; a++;
var b = Nat.FromNumber(20);
var c = a + b;
var d = Nat.FromNumber(2);
var e = b * c;
e--;
var f = c / d;
Console.WriteLine((e + f).ToNumber<int>()); // 593
record class Nat : IAdditionOperators<Nat, Nat, Nat>, IIncrementOperators<Nat>,
ISubtractionOperators<Nat, Nat, Nat>, IDecrementOperators<Nat>,
IMultiplyOperators<Nat, Nat, Nat>, IDivisionOperators<Nat, Nat, Nat>,
IModulusOperators<Nat, Nat, Nat>
{
private sealed record class Z : Nat;
private sealed record class S(Nat P) : Nat;
public static Nat Zero { get; } = new Z();
public static Nat One { get; } = new S(Zero);
public static Nat operator +(Nat left, Nat other) => left switch
{
Z => other,
S(var prev) => new S(prev + other),
_ => throw new InvalidOperationException("Invalid type."),
};
public static Nat operator ++(Nat value) => One + value;
public static Nat operator -(Nat left, Nat right) => (left, right) switch
{
(_, Z) => left,
(S(var lprev), S(var rprev)) => lprev - rprev,
(Z, _) => Zero,
_ => throw new InvalidOperationException("Invalid type."),
};
public static Nat operator --(Nat value) => value switch
{
Z => Zero,
S(var prev) => prev,
_ => throw new InvalidOperationException("Invalid type."),
};
public static Nat operator *(Nat left, Nat right) => (left, right) switch
{
(Z, _) or (_, Z) => Zero,
(S(var prev), _) => right + (prev * right),
_ => throw new InvalidOperationException("Invalid type."),
};
public static Nat operator /(Nat left, Nat right) => right switch
{
Z => throw new InvalidOperationException("Divided by zero."),
_ => (One + left - right) switch
{
Z => Zero,
S(var prev) => One + prev / right,
_ => throw new InvalidOperationException("Invalid type."),
}
};
public static Nat operator %(Nat left, Nat right) => left - left / right * right;
public T ToNumber<T>() where T : IBinaryInteger<T>
=> this is S(var inner) ? T.One + inner.ToNumber<T>() : T.Zero;
public static Nat FromNumber<T>(T number) where T : IBinaryInteger<T>
=> number > T.Zero ? new S(FromNumber(--number)) : Zero;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment