Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft macroless ==> #758

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

erikerlandson
Copy link
Contributor

A candidate fix for #755 that refactors ==> to be macroless: if a valid inference cannot be proven, then P1 ==> P2 will fail to manifest. It no longer has a boolean field that is checked via macro.

Introduces a compile-time version of Refined called RefinedLT, which tests a literal type L's value against a corresponding predicate P. So the use of macros has been pushed from ==> to RefinedLT, where the macros are used to extract literal-type value and run the validator against it.

This PR is currently a bit rough - a few unit tests are failing, or failing to compile, which appear to work OK when I run them in the REPL. I also hacked around the old .isValid based unit-testing using a shim that made kittens cry.

@erikerlandson
Copy link
Contributor Author

erikerlandson commented Apr 14, 2020

I have this passing[*] validateJVM locally, but it has to build against a version of singleton-ops with fthomas/singleton-ops#134, I'm using a publishLocal against head of master.

[*] a few things are disabled

@fthomas
Copy link
Owner

fthomas commented Apr 14, 2020

I applause the macroless ==>!

One quick question: Is RefinedLT only required to implement equalValidateInference or are there other reasons or instances it is required for?

@erikerlandson
Copy link
Contributor Author

@fthomas that's right, I only implemented RefinedLT to solve equalValidateInference. It seemed possibly useful as an implicit tool in its own right. For example, expressing refined-like constraints on type variables. But that's purely speculative.

@erikerlandson
Copy link
Contributor Author

Probably obvious from the PR diff, and my comments, but worth calling out that this does add singleton-ops as a new dependency.

@fthomas
Copy link
Owner

fthomas commented Apr 16, 2020

My thoughts with regards to equalValidateInference: If we accept that the Inference#isValid field was a mistake, then equalValidateInference was a mistake too. The instance was added without explanation in f1812d8 and is in the library since version 0.1.0. I guess my reasoning for adding it was something like this: if Inference requires a Boolean we can go from any value T Refined Equal[U] (which has the value U) to T Refined P by applying P to U to obtain that Boolean. So that instance either requires the questionable isValid field or another macro (RefinedLT). I think if we want to put refined in a better position for Scala 3 we should not trade one macro for another and remove equalValidateInference altogether.

WDYT, @erikerlandson?

@erikerlandson
Copy link
Contributor Author

erikerlandson commented Apr 16, 2020

I think if we want to put refined in a better position for Scala 3 we should not trade one macro for another and remove equalValidateInference altogether.

@fthomas I have no use cases that would need the equalValidateInference rule. If you are OK with removing it, it seems like a good trade-off for truly reducing the number of macros.

The role of expressing predicate constraints on literal types is arguably the domain of singleton-ops, using forms like OpAuxBoolean[P[T], true]

@erikerlandson
Copy link
Contributor Author

just as a use-case reference, here is how I'm applying ==> to constrain operations in type sound ways:
https://github.com/erikerlandson/coulomb/blob/refined/coulomb-refined/src/main/scala/coulomb/refined/package.scala#L154

@erikerlandson
Copy link
Contributor Author

@fthomas I removed RefinedLT and equalValidateInference. There were two impacts.

  1. this inference is no longer possible:
  property("Exists[A] ==> Exists[B]") = secure {
    Inference[Contains[W.`'5'`.T], Exists[Digit]].isValid
  }
  1. this assignment no longer compiles
    val a: Char Refined Equal[W.`'0'`.T] = '0'
    val b: Char Refined Digit = a

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants