All Downloads are FREE. Search and download functionalities are using the official Maven repository.

typequux.Nat.scala Maven / Gradle / Ivy

/**
  * Copyright 2019 Harshad Deo
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  * http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
package typequux

import Bool.{False, True}
import Comparison.{EQ, GT, LT}
import language.higherKinds
import Nat._

/** Peano encoding of natural numbers
  *
  * @author Harshad Deo
  * @since 0.1
  */
sealed trait Nat {

  /** Typeconstructor for querying whether this is zero or not
    *
    * @author Harshad Deo
    * @since 0.1
    */
  type Match[NonZero[N <: Nat] <: Up, IfZero <: Up, Up] <: Up

  /** Compares with the other peano number
    *
    * @author Harshad Deo
    * @since 0.1
    */
  type Compare[N <: Nat] <: Comparison

  /** Typelevel FoldRight
    *
    * @author Harshad Deo
    * @since 0.1
    */
  type FoldR[Init <: Type, Type, F <: Fold[Nat, Type]] <: Type

  /** Typelevel FoldLeft
    *
    * @author Harshad Deo
    * @since 0.1
    */
  type FoldL[Init <: Type, Type, F <: Fold[Nat, Type]] <: Type
}

/** Contains implementation traits for [[Nat]] and typeconstructor aliases that make usage more pleasant.
  *
  * 1. Additive commutativity:  +[A, B] =:= +[B, A]  
  *
  * 2. Additive associativity:  +[A, +[B, C]] =:= +[+[A, B], C] 
  *
  * 3. Additive identity:  +[A, _0] =:= A =:= +[_0, A] 
  *
  * 4. Multiplicative commutativity:  *[A, B] =:= *[B, A] 
  *
  * 5. Multiplicative associativity:  *[A, *[B, C]] =:= *[*[A, B], C] 
  *
  * 6. Multiplicative identity:  *[A, _1] =:= A =:= *[_1, A] 
  *
  * 7. Distributivity:  *[A, +[B, C]] =:= +[*[A, B], *[A, C]] 
  *
  * 8. Zero exponent:  ^[A, _0] =:= _1 
  *
  * 9. One exponent:  ^[_1, A] =:= _1 
  *
  * 10. Exponent Identity:  ^[A, _1] =:= A 
  *
  * 11. Total Order
  *
  *
  * @author Harshad Deo
  * @since 0.1
  */
object Nat {

  /** Represents zero in peano encoding of natural numbers
    *
    * @group Implementation
    * @author Harshad Deo
    * @since 0.1
    */
  final class Nat0 extends Nat {
    override type Match[NonZero[N <: Nat] <: Up, IfZero <: Up, Up] = IfZero
    override type Compare[N <: Nat] = N#Match[Nat.ConstLt, EQ, Comparison]
    override type FoldR[Init <: Type, Type, F <: Fold[Nat, Type]] = Init
    override type FoldL[Init <: Type, Type, F <: Fold[Nat, Type]] = Init
  }

  /** Represents a successor in the peano encoding of natural numbers
    *
    * @tparam N Peano-type to which this is a successor
    *
    * @group Implementation
    * @author Harshad Deo
    * @since 0.1
    */
  final class Succ[N <: Nat] extends Nat {
    override type Match[NonZero[M <: Nat] <: Up, IfZero <: Up, Up] = NonZero[N]
    override type Compare[M <: Nat] = M#Match[N#Compare, GT, Comparison]
    override type FoldR[Init <: Type, Type, F <: Fold[Nat, Type]] = F#Apply[Succ[N], N#FoldR[Init, Type, F]]
    override type FoldL[Init <: Type, Type, F <: Fold[Nat, Type]] = N#FoldL[F#Apply[Succ[N], Init], Type, F]
  }

  /** Peano 0
    *
    * @group Number aliases
    * @author Harshad Deo
    * @since 0.1
    */
  type _0 = Nat0

  /** Peano 1
    *
    * @group Number aliases
    * @author Harshad Deo
    * @since 0.1
    */
  type _1 = Succ[_0]

  /** Peano 2
    *
    * @group Number aliases
    * @author Harshad Deo
    * @since 0.1
    */
  type _2 = Succ[_1]

  /** Peano 3
    *
    * @group Number aliases
    * @author Harshad Deo
    * @since 0.1
    */
  type _3 = Succ[_2]

  /** Peano 4
    *
    * @group Number aliases
    * @author Harshad Deo
    * @since 0.1
    */
  type _4 = Succ[_3]

  /** Peano 5
    *
    * @group Number aliases
    * @author Harshad Deo
    * @since 0.1
    */
  type _5 = Succ[_4]

  /** Peano 6
    *
    * @group Number aliases
    * @author Harshad Deo
    * @since 0.1
    */
  type _6 = Succ[_5]

  /** Peano 7
    *
    * @group Number aliases
    * @author Harshad Deo
    * @since 0.1
    */
  type _7 = Succ[_6]

  /** Peano 8
    *
    * @group Number aliases
    * @author Harshad Deo
    * @since 0.1
    */
  type _8 = Succ[_7]

  /** Peano 9
    *
    * @group Number aliases
    * @author Harshad Deo
    * @since 0.1
    */
  type _9 = Succ[_8]

  private[Nat] type ConstFalse[X] = False
  private[Nat] type ConstLt[X] = LT

  /** Alias for getting the result of comparing two numbers
    *
    * @group Operations
    * @author Harshad Deo
    * @since 0.1
    */
  type Compare[A <: Nat, B <: Nat] = A#Compare[B]

  /** Alias for checking if the two numbers are equal
    *
    * @group Operations
    * @author Harshad Deo
    * @since 0.1
    */
  type ===[A <: Nat, B <: Nat] = A#Compare[B]#eq

  /** Alias for checking if the first number is less than the second
    *
    * @group Operations
    * @author Harshad Deo
    * @since 0.1
    */
  type <[A <: Nat, B <: Nat] = A#Compare[B]#lt

  /** Alias for checking if the first number is less than or equal to the second
    *
    * @group Operations
    * @author Harshad Deo
    * @since 0.1
    */
  type <=[A <: Nat, B <: Nat] = A#Compare[B]#le

  /** Alias for checking if the first number is greater than the second
    *
    * @group Operations
    * @author Harshad Deo
    * @since 0.1
    */
  type >[A <: Nat, B <: Nat] = A#Compare[B]#gt

  /** Alias for checking if the first number is greater than or equal to the second
    *
    * @group Operations
    * @author Harshad Deo
    * @since 0.1
    */
  type >=[A <: Nat, B <: Nat] = A#Compare[B]#ge

  /** Alias for checking if the number is zero
    *
    * @group Operations
    * @author Harshad Deo
    * @since 0.1
    */
  type IsO[A <: Nat] = A#Match[ConstFalse, True, Bool]

  /** Alias for adding two numbers
    *
    * @group Operations
    * @author Harshad Deo
    * @since 0.1
    */
  type +[A <: Nat, B <: Nat] = A#FoldR[B, Nat, IncFold]

  /** Alias for multiplying two numbers
    *
    * @group Operations
    * @author Harshad Deo
    * @since 0.1
    */
  type *[A <: Nat, B <: Nat] = A#FoldR[_0, Nat, SumFold[B]]

  /** Alias for computing the factorial of the number
    *
    * @group Operations
    * @author Harshad Deo
    * @since 0.1
    */
  type Fact[A <: Nat] = A#FoldL[_1, Nat, ProdFold]

  /** Alias for computing the exponent of the number
    *
    * @group Operations
    * @author Harshad Deo
    * @since 0.1
    */
  type ^[A <: Nat, B <: Nat] = B#FoldR[_1, Nat, ExpFold[A]]

  /** Alias for computing the square of the number
    *
    * @group Operations
    * @author Harshad Deo
    * @since 0.1
    */
  type Sq[A <: Nat] = A ^ _2

  /** Fold to compute the increment of a number
    *
    * @group Implementation
    * @author Harshad Deo
    * @since 0.1
    */
  trait IncFold extends Fold[Any, Nat] {
    override type Apply[E, Acc <: Nat] = Succ[Acc]
  }

  /** Fold to compute the sum
    *
    * @group Implementation
    * @author Harshad Deo
    * @since 0.1
    */
  trait SumFold[By <: Nat] extends Fold[Nat, Nat] {
    override type Apply[N <: Nat, Acc <: Nat] = By + Acc
  }

  /** Fold to compute the product
    *
    * @group Implementation
    * @author Harshad Deo
    * @since 0.1
    */
  trait ProdFold extends Fold[Nat, Nat] {
    override type Apply[N <: Nat, Acc <: Nat] = *[N, Acc]
  }

  /** Fold to compute the exponent
    *
    * @group Implementation
    * @author Harshad Deo
    * @since 0.1
    */
  trait ExpFold[By <: Nat] extends Fold[Nat, Nat] {
    override type Apply[N <: Nat, Acc <: Nat] = *[By, Acc]
  }

  /** Builds a value level representation of the [[Nat]]
    *
    * @tparam N Natural number for which the value level representation is being built
    *
    * @group Implementation
    * @author Harshad Deo
    * @since 0.1
    */
  final class NatRep[N <: Nat] private (val v: Int) extends AnyVal

  /** Provides implicit definitions to build a value level representation of a [[Nat]]
    *
    * @group Implementation
    * @author Harshad Deo
    * @since 0.1
    */
  object NatRep {

    /** Implements [[NatRep]] for [[Nat0]]
      *
      * @author Harshad Deo
      * @since 0.1
      */
    implicit val natRep0: NatRep[Nat0] = new NatRep[Nat0](0)

    /** Builds [[NatRep]] for [[Succ]]
      *
      * @author Harshad Deo
      * @since 0.1
      */
    implicit def natRepSucc[N <: Nat](implicit ev: NatRep[N]): NatRep[Succ[N]] = new NatRep(ev.v + 1)
  }

  /** Builds a value level representation of a [[Nat]]
    *
    * @tparam N Nat for which the value level representation is to be built
    *
    * @group Operations
    * @author Harshad Deo
    * @since 0.1
    */
  def toInt[N <: Nat](implicit ev: NatRep[N]): Int = ev.v
}

/** Marker trait for typelevel subtraction of [[Nat]]
  *
  * @tparam M Minuend
  * @tparam S Subtrahend
  * @tparam D Difference
  *
  * @author Harshad Deo
  * @since 0.1
  */
trait NatDiff[M <: Nat, S <: Nat, D <: Nat]

/** Contains implicit definitions to build a [[NatDiff]] marker
  *
  * @author Harshad Deo
  * @since 0.1
  */
object NatDiff {

  /** Base case for [[NatDiff]]
    *
    * @tparam M Minuend
    *
    * @author Harshad Deo
    * @since 0.1
    */
  implicit def natDiff0[M <: Nat]: NatDiff[M, Nat0, M] = new NatDiff[M, Nat0, M] {}

  /** Induction case for [[NatDiff]]
    *
    * @tparam MP Minuend - 1
    * @tparam SP Subtrahend - 1
    * @tparam D Difference
    *
    * @author Harshad Deo
    * @since 0.1
    */
  implicit def natDiffSucc[MP <: Nat, SP <: Nat, D <: Nat](
      implicit ev: NatDiff[MP, SP, D]): NatDiff[Succ[MP], Succ[SP], D] =
    new NatDiff[Succ[MP], Succ[SP], D] {}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy