Currently I have a piece of program that implements peano arithmetic:
sealed trait NaturalNumber
and a function called getResource that picks up natural number type-value in its arguments which have the interface:
sealed trait VersionNumber {
type Nat <: NaturalNumber
}
and checks the values against a reference type-value version numbers: MAJ and MIN, provided in this interface:
trait ResourceManifest {
def getResource: Int
type Major <: NaturalNumber
type Minor <: NaturalNumber
}
depending on which, the function does or does not compile. The function has this form:
def getResource(manifest: ResourceManifest)(maj: VersionNumber, min: VersionNumber)
(implicit
maj_check: manifest.Major IsEqual maj.Nat,
min_check: manifest.Minor IsLessOrEqual min.Nat
) = manifest.getResource
Here is the full code. (Here is an alternative implementation if you like type-recursion.)
As it is, this is powered by overriding type values which the average Scala user might not be too comfortable with. Also, getResource gets separate arguments for the major and minor versions.
Ideally I would like to user to provide values instead of types say in a wrapper class:
case class VersionInfo(major: VersionNumber, minor: VersionNumber)
so that my manifest is of this form:
trait ResourceManifestRefactored {
def getResource: Int
val versionInfo: VersionInfo
}
and similarly have:
def getResourceRefactored(manifest: ResourceManifestRefactored)(versionInfo: VersionInfo)
and do my type level constraints by picking up the version-types from the wrapper version value class: VersionInfo. However I am struggling to get it to work despite me doing it in many different ways. for instance I tried using doing my type checks directly with path-dependent types but that failed. I also tried defining MAJ and MIN based on the types in inside VersionInfo but the type constraints are no longer working the way they are expected to. I understand we are potentially facing the similar problems that are solved by the likes of aux-pattern but I am struggling to fit a similar solution to my problem.
Essentially, I want to have pre-defined objects wrapping types and I want to do type constraints through these objects instead of the types directly.
Is there a fundumental reason why I can't and if not, how can I do it?