CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-typelevel--algebra-2-13

Type classes for algebraic structures including basic algebraic structures, ring-like structures, and lattice-like structures in functional programming

Overview
Eval results
Files

priority-system.mddocs/

Priority System

The algebra library includes an advanced implicit resolution system for composable type class derivation. The Priority system allows fine-grained control over instance selection and provides fallback behavior for complex derivation scenarios.

Capabilities

Priority Type

The core Priority type represents a prioritized choice between a preferred and fallback value.

/**
 * Prioritized implicit search mechanism
 * Represents either a preferred value (P) or fallback value (F)
 */
sealed trait Priority[+P, +F] {
  /** Fold over the priority value */
  def fold[B](f1: P => B)(f2: F => B): B
  /** Join operation combining both types */
  def join[U >: P with F]: U
  /** Transform both preferred and fallback types */
  def bimap[P2, F2](f1: P => P2)(f2: F => F2): Priority[P2, F2]
  /** Convert to Either (preferred on left, fallback on right) */
  def toEither: Either[P, F]
  /** Test if this is a preferred value */
  def isPreferred: Boolean
  /** Test if this is a fallback value */
  def isFallback: Boolean
  /** Extract preferred value if present */
  def getPreferred: Option[P]
  /** Extract fallback value if present */
  def getFallback: Option[F]
}

Priority Constructors

Preferred

Represents a preferred implicit resolution.

/**
 * Preferred implicit resolution with highest priority
 */
case class Preferred[P](get: P) extends Priority[P, Nothing]

Fallback

Represents a fallback implicit resolution.

/**
 * Fallback implicit resolution with lower priority
 */
case class Fallback[F](get: F) extends Priority[Nothing, F]

Priority Object

Companion object providing construction and utility methods.

/**
 * Priority companion object
 */
object Priority {
  /** Get a Priority instance from implicit scope */
  def apply[P, F](implicit ev: Priority[P, F]): Priority[P, F]
}

Usage Example:

import algebra.Priority
import algebra.Priority._

// Create preferred priority
val preferred: Priority[String, Int] = Preferred("high priority")
val fallback: Priority[String, Int] = Fallback(42)

// Pattern matching
preferred match {
  case Preferred(value) => println(s"Got preferred: $value")
  case Fallback(value) => println(s"Got fallback: $value")
}

// Functional operations
val result = preferred.fold(
  pref => s"Preferred: $pref",
  fall => s"Fallback: $fall"
)  // "Preferred: high priority"

// Convert to Either
val either = preferred.toEither  // Right("high priority")

// Test priority level
val isPreferred = preferred.isPreferred  // true
val isFallback = preferred.isFallback    // false

Implicit Resolution Traits

FindPreferred

Internal trait for finding preferred instances.

/**
 * Private trait extending FindFallback for preferred instance resolution
 * Used internally by the Priority system for implicit resolution
 */
private trait FindPreferred extends FindFallback

FindFallback

Internal trait for finding fallback instances.

/**
 * Private trait for fallback instance resolution
 * Used internally by the Priority system for implicit resolution
 */
private trait FindFallback

Usage Patterns

Type Class Derivation

The Priority system is commonly used for automatic type class derivation where multiple valid instances might exist:

import algebra._
import algebra.Priority._

// Example: Deriving Monoid instances with priority
trait MonoidDerivation {
  // Preferred: Direct instance
  implicit def directMonoid[A](implicit ev: Monoid[A]): Preferred[Monoid[A]] = 
    Preferred(ev)
    
  // Fallback: Derived from Semigroup + identity
  implicit def derivedMonoid[A](implicit 
    semi: Semigroup[A], 
    zero: Zero[A]
  ): Fallback[Monoid[A]] = 
    Fallback(new Monoid[A] {
      def empty: A = zero.zero
      def combine(x: A, y: A): A = semi.combine(x, y)
    })
}

// Usage prioritizes direct instances over derived ones
def useMonoid[A](implicit priority: Priority[Monoid[A], Monoid[A]]): Monoid[A] = 
  priority.fold(identity, identity)

Instance Selection

Priority system helps resolve ambiguous implicits:

import algebra.Priority._

trait MultipleInstancesExample {
  // High priority instance
  implicit def highPriorityString: Preferred[String] = Preferred("high")
  
  // Low priority instance  
  implicit def lowPriorityString: Fallback[String] = Fallback("low")
  
  // Resolution will pick preferred over fallback
  def resolve(implicit priority: Priority[String, String]): String = 
    priority.fold(preferred = identity, fallback = identity)
}

val example = new MultipleInstancesExample {}
val result = example.resolve  // "high" (preferred wins)

Composable Derivation

Priority enables composable derivation strategies:

import algebra._
import algebra.ring._
import algebra.Priority._

trait ComposableDerivation {
  // Strategy 1: Direct Ring instance (highest priority)
  implicit def directRing[A](implicit ev: Ring[A]): Preferred[Ring[A]] = 
    Preferred(ev)
    
  // Strategy 2: Construct from components (fallback)
  implicit def constructedRing[A](implicit
    add: AdditiveCommutativeGroup[A],
    mult: MultiplicativeMonoid[A],
    // Additional constraints...
  ): Fallback[Ring[A]] = 
    Fallback(new Ring[A] {
      def zero: A = add.zero
      def one: A = mult.one
      def plus(x: A, y: A): A = add.plus(x, y)
      def times(x: A, y: A): A = mult.times(x, y)
      def negate(x: A): A = add.negate(x)
      def fromInt(n: Int): A = ??? // Implementation
      def fromBigInt(n: BigInt): A = ??? // Implementation
    })
}

Error Handling and Debugging

Priority system aids in debugging implicit resolution:

import algebra.Priority._

trait DebuggingExample {
  def debugPriority[P, F](implicit priority: Priority[P, F]): Unit = {
    priority match {
      case Preferred(value) => 
        println(s"Using preferred instance: ${value.getClass.getSimpleName}")
      case Fallback(value) => 
        println(s"Using fallback instance: ${value.getClass.getSimpleName}")
    }
  }
  
  // Usage
  def example[A](implicit priority: Priority[Ring[A], Ring[A]]): Ring[A] = {
    debugPriority(priority)  // Shows which instance was selected
    priority.fold(identity, identity)
  }
}

Advanced Patterns

Nested Priorities

Priorities can be nested for complex resolution strategies:

import algebra.Priority._

trait NestedPriorities {
  type HighPriority[A] = Preferred[A]
  type MediumPriority[A] = Fallback[Preferred[A]]
  type LowPriority[A] = Fallback[Fallback[A]]
  
  def resolveTiered[A](implicit 
    priority: Priority[HighPriority[A], Priority[MediumPriority[A], LowPriority[A]]]
  ): A = {
    priority.fold(
      high = _.get,
      fallback = _.fold(
        medium = _.get.get,
        low = _.get.get.get
      )
    )
  }
}

Context-Sensitive Derivation

Priority enables context-sensitive instance derivation:

import algebra.Priority._

trait ContextSensitive {
  // Context marker traits
  sealed trait FastContext
  sealed trait PreciseContext
  
  // Different strategies for different contexts
  implicit def fastRing[A](implicit 
    ctx: FastContext,
    base: Ring[A]
  ): Preferred[Ring[A]] = Preferred(base)  // Use base implementation
  
  implicit def preciseRing[A](implicit
    ctx: PreciseContext, 
    enhanced: EnhancedRing[A]
  ): Preferred[Ring[A]] = Preferred(enhanced.asRing)  // Use enhanced version
  
  // Fallback when no context
  implicit def defaultRing[A](implicit base: Ring[A]): Fallback[Ring[A]] = 
    Fallback(base)
}

Integration with Type Classes

The Priority system integrates seamlessly with algebra's type class hierarchy:

Automatic Instance Resolution

import algebra._
import algebra.instances.all._
import algebra.Priority._

// The system automatically selects the best available instance
def useAlgebraicStructure[A](implicit 
  priority: Priority[Ring[A], Priority[Monoid[A], Semigroup[A]]]
): String = {
  priority.fold(
    ring => "Using Ring operations",
    fallback => fallback.fold(
      monoid => "Using Monoid operations", 
      semigroup => "Using Semigroup operations"
    )
  )
}

// Usage examples
useAlgebraicStructure[Int]     // "Using Ring operations"
useAlgebraicStructure[String]  // "Using Monoid operations"  
useAlgebraicStructure[List[Int]] // "Using Monoid operations"

Custom Derivation Rules

import algebra.Priority._

trait CustomDerivation {
  // Rule: Prefer CommutativeRing over Ring when available
  implicit def commutativeRingPriority[A](implicit 
    cr: CommutativeRing[A]
  ): Preferred[Ring[A]] = Preferred(cr)
  
  // Rule: Use regular Ring as fallback
  implicit def regularRingFallback[A](implicit 
    r: Ring[A]
  ): Fallback[Ring[A]] = Fallback(r)
  
  // Consumer gets the best available Ring
  def optimizedRingOp[A](implicit 
    priority: Priority[Ring[A], Ring[A]]
  ): Ring[A] = priority.fold(identity, identity)
}

This Priority system enables sophisticated implicit resolution strategies while maintaining type safety and predictable behavior in complex algebraic derivation scenarios.

Install with Tessl CLI

npx tessl i tessl/maven-org-typelevel--algebra-2-13

docs

basic-structures.md

index.md

instances.md

lattice-structures.md

priority-system.md

ring-structures.md

tile.json