Skip to content
Snippets Groups Projects

[#854] Make WithDeMorganScope instances more principled

Merged David Feuer requested to merge dfeuer/#854-principled-de-morgan into master

Description

Make WithDeMorganScope instances more principled, avoiding a non-compiler-checked "impossible" error.

Related issue(s)

Retain type information for a bit longer to let GHC check our work in withDeMorganScope instances.

Resolves #854 (closed)

:white_check_mark: Checklist for your Merge Request

Related changes (conditional)

  • Tests (see short guidelines)

    • If I added new functionality, I added tests covering it.
    • If I fixed a bug, I added a regression test to prevent the bug from silently reappearing again.
  • Documentation

    • I checked whether I should update the docs and did so if necessary:
    • I updated changelog files of all affected packages released to Hackage if my changes are externally visible.

Stylistic guide (mandatory)

Edited by David Feuer

Merge request reports

Loading
Loading

Activity

Filter activity
  • Approvals
  • Assignees & reviewers
  • Comments (from bots)
  • Comments (from users)
  • Commits & branches
  • Edits
  • Labels
  • Lock status
  • Mentions
  • Merge request status
  • Tracking
1050 1045 instance (SingI a, SingI b) => WithDeMorganScope HasNoOp 'TPair a b where
1051 withDeMorganScope = mkWithDeMorgan @HasNoOp @a @b
1046 withDeMorganScope f
1047 | Refl <- orL @(ContainsOp a) @(ContainsOp b)
1048 , Refl <- orR @(ContainsOp a) @(ContainsOp b)
1049 = f
1050
1051 orL :: (a || b) ~ 'False => a :~: 'False
1052 orL = unsafeCoerce Refl
1053
1054 orR :: (a || b) ~ 'False => b :~: 'False
1055 orR = unsafeCoerce Refl
1056
1057 We'd presumably want to use RULES to rewrite more principled instances
1058 to do this sort of thing instead. But can we do it reasonably nicely
1059 without hand-writing two implementations for each instance?
  • Let's take HasNoOp t as an example. We have an instance if ContainsOp t ~ 'False -- which we can conjure into existence from thin air with unsafeCoerce. For it to be safe, we need to be sure that ContainsOp t indeed evaluates to False, but that will be verified by the inefficient code. And the efficient code essentially boils down to

    unsafeWithDeMorganScope f =
      case (unsafeCoerce Refl :: ContainsOp t :~: 'False) of
        Refl -> f

    which we can generalize using type applications to accept the family we need to unsafeCoerce as a parameter. Which we can then directly use in rule definitions. So, one ambiguous polymorphic helper function and one rule per instance with explicit type binders.

    I'm sure there are some gotchas, but at first glance this seems workable?

    Edited by Nikolay Yakimov
  • If we're going to do something unsafe, I'd prefer to keep the trusted base as small as possible, as in OrL and OrR. So I'm imagining maybe a singletons-like defunctionalization of the type families so we can talk about ideas like "The passed type family works like this when passed this sort of structure with these substructures".

  • "Unsafe" is a relative term here. As long as GHC actually uses the "inefficient but verifiable" implementation to typecheck everything and then substitutes the appropriate "unsafe" one, the "unsafe" one is as safe as the "inefficient" one. One possible gotcha I see here is a mistake in rewriting rules would end up in a segfault. But that's something we'll have to make peace with regardless.

  • David Feuer changed this line in version 3 of the diff

    changed this line in version 3 of the diff

  • As I expected, I was able to get it down to one, pretty much legitimate, rule. The process of figuring out how to go from two rules to one had the side benefit of pointing out how to go from two SingI constraints in each instance down to one, which is kind of neat.

  • Please register or sign in to reply
  • David Feuer added 1 commit

    added 1 commit

    Compare with previous version

  • Serokell Bot added 1 commit

    added 1 commit

    Compare with previous version

  • Serokell Bot marked this merge request as draft from 372bf978

    marked this merge request as draft from 372bf978

  • David Feuer added 1 commit

    added 1 commit

    Compare with previous version

  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Please register or sign in to reply
    Loading