google / google/codeworld

Replace codeworld-base `==` with GHC source plugins

Offen
#687 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
discussion
Vorherrschende Sprache
Haskell
Sterne
1.3k
Forks
201
PR-Merge-Kennzahlen
Keine gemergten PRs in 30 T.

Beschreibung

This has to wait on GHCJS to catch up to 8.6, but I'm creating this issue to document the plan.

## The current state

`codeworld-base` implements a polymorphic `(==) :: a -> a -> Bool` using some JavaScript that @luite wrote, that walks the GHCJS heap, and compares for structural equality. This works, but it has a few drawbacks.

1. I worry about performance, since comparisons happen a lot. (There are some rewrite rules to revert to Haskell's `==` for common types, but they might not be firing.)
2. The main problem is that it ties `codeworld-base` to GHCJS. Code written with `codeworld-api` can now be compiled natively using `blank-canvas`, but this doesn't work for `codeworld-base`. That, in turn, means that we can only do mobile applications via a JavaScript wrapper, which is likely to be too slow on older phones. And if https://github.com/WebGHC/ghc ever gets off the ground, we'll be blocked from migrating there, as well, since the heap won't be so easily introspected.

## The long-term plan

We may be able to switch back to Haskell's `==` operator, if we can solve two problems. First, how do we let a student compare values of their own types without deriving `Eq` instances? And second, how do we let users write explicit type annotations without specifying constraints when they use polymorphic equality?

The first problem can be solved by making sure that appropriate `Eq` instances exist when they are needed, and add them to type declarations. This is easy to do with types declared in `codeworld-base`. It appears we can now write a GHC source plugin that will automatically derive `Eq` for student-defined types.

The second problem can be solved by rewriting type annotations to always include an [extra constraints wildcard](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#extra-constraints-wildcard). It appears this can also be done in a GHC source plugin.

Some related bookeeping:

* We need `-XPartialTypeSignatures -Wno-partial-type-signatures` to avoid warnings or errors for the partial type signatures. It's vaguely disappointing that we can't get warnings for user-specified partial types. (I definitely don't want warnings to bug students before they learn about type annotations, but I enjoy being able to tell them to just write `foo :: _` to ask the compiler what type something has.) But it's a minor loss.
* When displaying the `codeworld-base` documentation in the guide, we'd need to hide `Eq` constraints, the same way we already hide `HasCallStack`.
* We'd need to rewrite error messages for missing `Eq` instances with something more friendly, like "Functions, pictures, or types that contain them, cannot be compared." (`Picture`s are included because they have a semantics as `Point -> Color` which doesn't agree with any definable `Eq` instance.) Or, probably even better, just declare an `Eq` instance for functions and `Picture`s that fails at runtime. That should then make pretty much anything comparable that can be written with just `codeworld-base`. (except extremely large tuples, I guess... but we can get large enough.)

If this is done for `Eq`, we could also revisit `Ord` and `Show`, adopting the same approach there. `Picture` and function values should have `Show` instances that just print "\<\\>" or "\<\\>", rather than failing, and infinite (or long) lists should automatically ellipsize. It's really exciting to be able to print state values, which usually have user-defined types, when debugging!)

## The short-term option

After thinking this through, I wonder how often `codeworld-base` users really compare equality of user-defined types or write explicit type signatures where they need polymorphic equality, anyway. I imagine it's not very common. It might be feasible to migrate `Eq` *now*, breaking the rare program that does one of these things.

I suspect it's a bit more common for user programs to compare `Picture` or function values, which "works" now, even though the results are semantically wrong. I'm okay with breaking these (already broken) programs. But I do wish we could warn these students for a bit first.

It might be possible to fake warnings from the JavaScript implementation of `==`, before switching.
Or, after switching, https://ghc.haskell.org/trac/ghc/ticket/12014 seems to propose deprecating instances, but it appears it was not implemented.

Beitragsleitfaden

Beitragsleitfaden öffnen

Rechercherichtung

No files or tests are named. Start by reviewing the current codeworld-base JavaScript implementation of polymorphic equality and the GHCJS 8.6 dependency, then evaluate the proposed GHC source-plugin approach; done would include handling derived Eq instances and partial type signatures without the current GHCJS-specific implementation.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
haskell
Bereich
compilers
Issue-Typ
Feature
Schwierigkeit
5/5
Geschätzter Aufwand
Über eine Woche
Aktivitätsstatus
Veraltet
Klarheit
Muss geklärt werden
Anfängerfreundlichkeit
20/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.