Type check for polymorphic function types
See original GitHub issueCompiler version
3.1.2-RC1-bin-20211102-82172ed-NIGHTLY
Minimized code
I’ve found it really hard to minimize this due too all the moving components. You can click the little triangle to see the full attempt.
Here are the bits where I think it goes wrong:
// a generated group of tests for type V
// reduced from a collection of these
val condUpperBoundPartialOrdering: [V] => () => TestGroup[V]
// a function that check if a group of tests applies to a specific object
// inline here is necessary for it to work (the positive case)
inline def appliesTo[V](tl: TestLattice[_, V], v: TestGroup[V]): Boolean
// applying the test check to an object
// reduced form a "reduce"
def app[X, Y](x: X, f: X => Y): Y
// a generated group of tests for type V
// reduced from a collection of these
val condUpperBoundPartialOrdering: [V] => () => TestGroup[V]
// a function that check if a group of tests applies to a specific object
// inline here is necessary for it to work (the positive case)
inline def appliesTo[V](tl: TestLattice[_, V], v: TestGroup[V]): Boolean
// applying the test check to an object
// reduced form a "reduce"
def app[X, Y](x: X, f: X => Y): Y
// Necesarry abstract definitions
trait JoinLattice[A] extends PartialOrdering[A]:
override def tryCompare(x: A, y: A): Option[0 | 1 | -1] = ???
override def lteq(x: A, y: A): Boolean = ???
trait UpperBound[A]
trait LowerBound[A]
trait Finite[A]:
val elements: Set[A]
trait Atomic[A] extends LowerBound[A]
trait CoAtomic[A] extends UpperBound[A]
trait BoundedJoinLattice[A] extends JoinLattice[A] with LowerBound[A]
trait DoubleBoundedJoinLattice[A] extends BoundedJoinLattice[A] with UpperBound[A]
trait AtomicJoinLattice[A] extends BoundedJoinLattice[A] with Atomic[A]
trait BoundedCoAtomicJoinLattice[A] extends BoundedJoinLattice[A] with CoAtomic[A]
trait DoubleAtomicJoinLattice[A] extends BoundedCoAtomicJoinLattice[A] with AtomicJoinLattice[A]
trait FiniteDoubleAtomicJoinLattice[A] extends DoubleAtomicJoinLattice[A] with Finite[A]
// Necesarry concrete definitions
def optionsLattice[A](options: Seq[A]) = new FiniteDoubleAtomicJoinLattice[Set[A]]:
val elements = options.toSet.subsets.toSet
def evidenceLattice[A] = new BoundedJoinLattice[(Set[A], Set[A])] {}
// Test utils
abstract class TestGroup[V]:
type R
val group: String
case class TestLattice[R, V](val name: String, lattice: R, elements: Iterable[V]):
type Lattice = R
type Carrier = V
object TestLattice:
def fromFinite[R <: Finite[V], V](name: String, lattice: R) =
TestLattice(name, lattice, lattice.elements)
// Util for example
def app[X, Y](x: X, f: X => Y) = f(x)
inline def appliesTo[V](tl: TestLattice[_, V], v: TestGroup[V]) =
tl.lattice match
case q: v.R => println(("matches", v, q))
case q => println(("misses", v, q))
// Values for example
val to_test = Seq(
TestLattice("Evidence (Set, Set)", evidenceLattice[Int], {
val range = (0 to 3).toSet.subsets.toSet
for x <- range; y <- range yield (x, y)
}),
TestLattice.fromFinite("Options (Set)", optionsLattice(1 to 4))
)
val condUpperBoundPartialOrdering = [V] => () => new TestGroup[V]:
type R = UpperBound[V] & PartialOrdering[V]
val group = "UpperBound PartialOrdering laws"
@main def example =
for ins <- to_test do
// this works correctly
app(condUpperBoundPartialOrdering[ins.Carrier](), v => appliesTo(ins, v))
// this does not compile
// app(condUpperBoundPartialOrdering, v => appliesTo(ins, v[ins.Carrier]()))
Output
[error] | app(condUpperBoundPartialOrdering, v => appliesTo(ins, v[ins.Carrier]()))
[error] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[error] |Found: ([V] => () => TestGroup[V]{R = IP.lib.UpperBound[V] & PartialOrdering[V]}) =>
[error] | Unit
[error] |Required: ([V] => () => TestGroup[Any]{R = IP.lib.UpperBound[Any] & PartialOrdering[Any]}) =>
[error] | Unit
Expectation
Work the same as
app(condUpperBoundPartialOrdering[ins.Carrier](), v => appliesTo(ins, v))
Two things here:
- I kinda expect
([V] => () => TestGroup[V]{R = IP.lib.UpperBound[V] & PartialOrdering[V]})
to match type([V] => () => TestGroup[Any]{R = IP.lib.UpperBound[Any] & PartialOrdering[Any]})
? - I expect
(λx.G) (f v)
to be equivalent to(λx.G[x := (f x)]) v
.
Issue Analytics
- State:
- Created 2 years ago
- Comments:7 (4 by maintainers)
Top Results From Across the Web
Polymorphic Function Types - Scala 3
A polymorphic function type is a function type which accepts type parameters. ... Here is how to implement this using polymorphic function types:....
Read more >Polymorphic Function Types
This type describes function values which take a type A as a parameter, then take a list of type List[A] , and return...
Read more >Type polymorphic functions in TypeScript - Zhenghao
Type polymorphic functions in TypeScript · The argument str has the string union type "int" | "char" , and to make the return...
Read more >Basic Polymorphic Typechecking - Luca Cardelli
Parametric polymorphic type systems share with Algol 68 properties of compile-time checking, static typing and treatment of higher-order functions, ...
Read more >Handout 6: Polymorphic Type Systems
Polymorphic functions. A function that can take arguments of different types or return results of different types, is called a polymorphic function.
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
What you are doing in this example relies on static types to work, so I can only to suggest that you zip each
Cond
with a test when you construct theSeq