google / google/codeworld

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

Aperta
#687 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub
discussion
Lingua principale
Haskell
Stelle
1.3k
Fork
201
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Descrizione

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.

Guida per i contributori

Apri la guida per i contributori

Direzione di ricerca

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.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
haskell
Ambito
compilers
Tipo di issue
Funzionalità
Difficoltà
5/5
Tempo stimato
Più di una settimana
Stato di attività
Ferma
Chiarezza
Da chiarire
Idoneità per principianti
20/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.