Opened 3 years ago

Closed 2 years ago

Last modified 23 months ago

#9590 closed bug (wontfix)

AMP breaks `haskell2010` package

Reported by: hvr Owned by:
Priority: high Milestone: 7.10.1
Component: Core Libraries Version: 7.9
Keywords: AMP, report-impact Cc: ekmett, thoughtpolice, core-libraries-committee@…
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: GHC rejects valid program Test Case:
Blocked By: Blocking:
Related Tickets: Differential Rev(s): Phab:D510
Wiki Page:

Description (last modified by hvr)

(and probably also haskell98)

I hate to be the one pointing this out, but the AMP has one ugly side-effect:

As of now, GHC HEAD rejects Haskell2010 programs (which know nothing about the Applicative class). Moreover, there's no simple way to access the Applicative class in order to write an instance to satisfy non-standard superclass requirement, so it's impossible to define custom Monad instances.

For instance, consider the following session which worked in GHC 7.6.3 (albeit with an AMP warning):

$ inplace/bin/ghc-stage2 --interactive -XHaskell2010 -hide-all-packages -package haskell2010
GHCi, version 7.9.20140914: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim-0.3.1.0 ... linking ... done.
Loading package integer-gmp-0.5.1.0 ... linking ... done.
Loading package base-4.8.0.0 ... linking ... done.
Loading package array-0.5.0.1 ... linking ... done.
Loading package haskell2010-1.1.2.1 ... linking ... done.

λ:2> data Identity a = Identity a
data Identity a = Identity a

λ:3> instance Monad Identity

<interactive>:3:10:
    No instance for (base-4.8.0.0:GHC.Base.Applicative Identity) arising from the superclasses of an instance declaration
    In the instance declaration for ‘Monad Identity’

λ:4> :info Monad
class base-4.8.0.0:GHC.Base.Applicative m => Monad (m :: * -> *) where
  (>>=) :: m a -> (a -> m b) -> m b
  (>>) :: m a -> m b -> m b
  return :: a -> m a
  fail :: String -> m a
  	-- Defined in ‘base-4.8.0.0:GHC.Base’
instance Monad (Either e) -- Defined in ‘base-4.8.0.0:Data.Either’
instance Monad Maybe -- Defined in ‘base-4.8.0.0:Data.Maybe’
instance Monad [] -- Defined in ‘base-4.8.0.0:GHC.Base’
instance Monad IO -- Defined in ‘base-4.8.0.0:GHC.Base’
instance Monad ((->) r) -- Defined in ‘base-4.8.0.0:GHC.Base’

λ:5> 

Change History (24)

comment:1 Changed 3 years ago by hvr

Description: modified (diff)

comment:2 Changed 3 years ago by hvr

Cc: ekmett thoughtpolice added

One obvious way to fix this would be to have haskell2010 have its own Monad typeclass, but this would make it incompatible with base's Monad, effectively breaking interoperability between packages depending on base and those depending on haskell2010...

comment:3 Changed 3 years ago by ekmett

The fact that the AMP broke strict Haskell2010 compatibility for the haskell2010 package was a known going in. We already broke it with Num a few years ago.

We really have two options going forward.

We can say that haskell2010 and haskell98 and the like are what they are, rough compatibility shims that get you as close as we can to the semantics of those standards without breaking compatibility with other packages...

Or we can sink more effort into making them more accurate to their corresponding standards but in the process doom any code that bothers to compile with them to second-class citizen status.

I'm rather ambivalent about the choice we make here.

So the question comes down to: who is the audience of haskell2010 the package?

Is it educators who want a given standard they can teach to? Folks who have students who mayl eventually cast off the training wheels and move on to write real GHC if they want to build code that fits with the rest of the ecosystem?

Or is it users who don't want to let a GHC monoculture set the standard and would prefer to work with a smaller subset of the language, but still want to have access to the ecosystem of packages through cabal? Folks who may have other compilers in mind, who would prefer to implement against a standard or at least have the ability to have their code compile against a compiler that implements the standard.

If it is the former, then the story of making haskell2010-specific Monad and Num classes with their own supplies of instances has some merit.

If it is the latter, we'd cripple the ability of that group to work with both packages to make haskell2010 and haskell98 export their own version of Monad and Num.

I'm personally inclined to go with the status quo, which is that haskell2010 is a fairly weak compatibility shim that more directly suits the needs of the second audience, if only because it is the audience who can grow the most, and it takes the least amount of effort investiture on our behalf.

If, however, a champion were to stand up and offer to do all the work to maintain a more pedantic haskell2010 package replete with its own instances for its own Monad / Num, I wouldn't stand in their way.

Frankly, as it stands that could probably be done as an end user project without really involving any input from GHC HQ.

If that were done it needn't even conflict with the existing haskell2010 package.

So, with that in mind I'd be content to see the existing package for what it is, and push back the effort to make a better shim on the user who actually wants to confront all the issues involved.

comment:4 Changed 3 years ago by hvr

Description: modified (diff)

(point out the problem in the description more explicitly)

comment:5 Changed 3 years ago by ekmett

Ack! Now I see what you mean.

Applicative not even being in the package _is_ a problem.

comment:6 Changed 3 years ago by singpolyma

Or is it users who don't want to let a GHC monoculture set the standard and would prefer to work with a smaller subset of the language, but still want to have access to the ecosystem of packages through cabal? Folks who may have other compilers in mind, who would prefer to implement against a standard or at least have the ability to have their code compile against a compiler that implements the standard.

This is me. My primary use of the haskell2010 package is to test my code against it, as well as base, in order to check that it is more likely to work on a standards-conformant Haskell implementation.

To that end, I would prefer it if haskell2010 were basically just cut-n-paste the code from the report and be done with it. This would mean a different Monad instance, which I gather might cause some complexity for do notation (though will it really? GHC already has rebindable do, it seems like this would just be a special case of that).

comment:7 Changed 3 years ago by ekmett

It is a bit more complex than just pasting the report. GHC internals actually know where Monad comes from for instance, so you'd have knock-on consequences.

If we _do_ adopt a haskell2010 fully standards compliant package:

1.) We'd need to make some modifications to GHC itself to tell it where to desugar to for the Monad syntax and internal hackery. We'd need to figure out how to tell tools like cabal to do the right thing.

2.) Code that previously worked with the haskell2010 or haskell98 packages would cease to work with base and vice versa where those instances are concerned. You'd be giving up, say, containers, not just the rest of base. This actually comes at a price to a dozen or two packages that are built right now with the haskell98 package and with these other dependencies as well, possibly breaking in non-obvious ways.

It may be that to fully support both of these two very different usecases for haskell2010 that you'd get two haskell2010-like packages to support both user pools.

This makes for a very complex story to explain to end users, and a lot of engineering.

Last edited 3 years ago by ekmett (previous) (diff)

comment:8 Changed 3 years ago by simonpj

Component: libraries/haskell2010Core Libraries
Owner: set to ekmett

I'm open to whatever the Core Libraries committee thinks is best here, including discussing magical GHC support for whatever you need. I confess that I am reluctant to invest much GHC-development effort in this, but I respect the need to avoid killing off lots of useful libraries by mistake.

Hence making "Core Libraries" the "Component". (We are removing libraries/* components... too much noise.)

Simon

comment:9 Changed 3 years ago by singpolyma

We'd need to make some modifications to GHC itself to tell it where to desugar to for the Monad syntax and internal hackery. We'd need to figure out how to tell tools like cabal to do the right thing.

Isn't this already needed for RebindableSyntax? Is this not a special case of that, or it more different than I think?

comment:10 in reply to:  9 Changed 3 years ago by hvr

Replying to singpolyma:

Isn't this already needed for RebindableSyntax? Is this not a special case of that, or it more different than I think?

Here's some sketchy idea I also wrote in a reddit comment about an hypothetical RebindableSyntax-variant called ExportedRebindedSyntax (modulo bikeshed):

  • Code using a non-default Prelude (like e.g. haskell2010 or haskell98) shall just need to hide the base package and bring haskell2010 into scope
  • Particularly, code importing that non-default Prelude shall not need to enable any language extensions
  • The non-default Prelude module would rebind all syntax elements like with RebindableSyntax, but it would only export the desugaring rules, but does not need to export the symbols such as IfThenElse the desugaring rules are bound to for client code to work
  • If a module X directly or indirectly imports a Prelude module using the ExportedRebindedSyntax extension, it inherits the desugaring rules, and exports them to other modules that import that module X. It would be illegal to have conflicting desugaring rules brought into scope (c.f. conflicting typeclass instances being an error)

comment:11 in reply to:  5 Changed 3 years ago by hvr

Cc: core-libraries-committee@… added

Replying to ekmett:

Ack! Now I see what you mean.

Applicative not even being in the package _is_ a problem.

As a reminder this is still an issue, here's a suggestion together with a counter-argument:

As a pragmatic solution, one could simply make available the Applicative typeclass in haskell2010. That way you can define Monad instance, iff you also define Functor and Applicative instances.

However, now you end up with a "Haskell2010" program that works with GHC 7.10 but not GHC 7.{0,2,4,8} (or any other strict-Haskell2010 mode compiler), as the program refers to a non-standard Applicative only available in GHC 7.10.

comment:12 Changed 3 years ago by ekmett

There is no silver bullet here.

The more I think on it, the more it strikes me that the best option is for us to just give up on these packages as a failed experiment.

Neither package has ever really received any traction or picked up a coherent usage story. Every attempt folks (including me) have made to put forth them as something someone might use in practice has been rather rightly derided as unrealistic.

We'd also get to clear old-locale and old-time out of the core.

Any solution that involves bringing Applicative in could just as well be done outside of the GHC development process, so if a user base wanted to rally behind a haskell98 / haskell2010 package, it could be built out in cabal by anyone; we could put out a call for an active maintainer who wants to own it.

It is only if we wanted to isolate haskell2010 users further from the community by making them use their own Monad, etc. that we might have to keep haskell2010 and haskell98 as core packages -- but then only for compiler support for do sugar, and even that could probably be done with enough work. It doesn't strike me as a thing we're remotely ready to do though. It isn't clear it'd work sufficiently well for any appreciable number of users to at all justify the time and maintenance.

Which brings us back to the option of just cutting these packages loose.

Last edited 3 years ago by ekmett (previous) (diff)

comment:13 Changed 3 years ago by thoughtpolice

Differential Rev(s): Phab:D510

comment:14 Changed 3 years ago by Austin Seipp <austin@…>

In 6efe5729252ea50843e1b04e21c7a3e1769a3434/ghc:

Don't build old-{time,locale} and haskell{98,2010}

Summary:
As discussed on ghc-devs@haskell.org and the trac ticket, we're removing
these packages from the 7.10 release as they no longer work correctly,
and can't easily be made to properly follow the standard as `base`
changes over time.

This does not remove the packages from the tree, only the build system.

https://www.haskell.org/pipermail/ghc-devs/2014-November/007357.html

Signed-off-by: Austin Seipp <austin@well-typed.com>

Test Plan: iiam

Reviewers: hvr, ekmett

Reviewed By: hvr, ekmett

Subscribers: thomie, carter

Differential Revision: https://phabricator.haskell.org/D510

GHC Trac Issues: #9590

comment:15 Changed 3 years ago by Austin Seipp <austin@…>

In 86dda8f7adb887eb376a938dd48780e503b53a08/ghc:

Delete old-{time,locale} and haskell{98,2010}

Summary:
Depends on D510. This is the final blow and removes them from
the tree completely.

Signed-off-by: Austin Seipp <austin@well-typed.com>

Test Plan: I looked really hard but didn't see them.

Reviewers: hvr, ekmett

Subscribers: thomie, carter

Differential Revision: https://phabricator.haskell.org/D511

GHC Trac Issues: #9590

comment:16 Changed 3 years ago by thoughtpolice

Resolution: fixed
Status: newclosed

Fixed.

comment:17 Changed 3 years ago by hvr

Keywords: report-impact added

comment:18 Changed 3 years ago by hvr

Fyi, here's an attempt at updating/reviving the haskell2010 package:

http://git.haskell.org/packages/haskell2010.git/commitdiff/refs/heads/wip/T9590

but it's unsatisfying at this moment; as expected, do-syntax still refers to the base-version of the Monad-class, so you need to use -XRebindableSyntax and be careful to bring into local scope whatever functions are needed for syntax desugaring.

Maybe we can improve the alternative-Prelude support in GHC 7.12 to allow a more seamless -XRebindableSyntax support which is less brittle, and allows to better emulate a strict haskell2010 mode, which only requires to select the respective -XHaskell.... flag for the language-part, and the respective Prelude-providing library-package instead of base, and would then drop you into a (reasonably) strictly standard-conforming language+std-library environment...

comment:19 Changed 3 years ago by hvr

Even something like {-# LANGUAGE RebindableSyntax=haskell2010:Prelude.Syntax -#} would already be an improvement with the following semantic:

  • desugaring like -XRebindableSyntax,
  • *but* rather than the local scope, only what's exported by the Prelude.Syntax module (from the haskell2010 package) is used for desugaring,
  • and Prelude.Syntax can be a hidden module of the haskell2010 package (to avoid polluting the module namespace)

This could allow (maybe) to write a simple shell-script wrapper ghci2010 (or ghc2010) in the style of

#!/bin/sh

ghci -XHaskell2010 \
  -hide-all-packages -package haskell2010 \
  -XRebindableSyntax=haskell2010:Prelude.Syntax $*

This is similar to the {-# LANGUAGE Prelude=AlternatePrelude #-} idea we were floating recently, but also takes into account desugaring.

NB: this doesn't solve the issue of packages compiled against base and haskell2010 to have diverging typeclass hierarchies. But I don't think we can solve that without a significant amount of complexity. I'd rather suggest to instead have packages actively support haskell2010 (maybe as Cabal configuration option via flags, or via hs2010-compat-layer packages -- not sure yet which is best) for those few packages where there's enough demand to (like e.g. something like containers).

My main motivation for a haskell2010 package is to have a reference implementation for the Haskell 2010 report (which can be useful for teaching, or for being able to compile some ancient "pure" Haskell2010 code with the latest GHC), rather than having full Hackage compatibility...

comment:20 Changed 3 years ago by hvr

Agda seems to have support via pragmas to inform the compiler about desugaring primitives (citing https://pay.reddit.com/r/haskell/comments/2vzqqa/picking_your_prelude/comxs6z):

Agda has a nice mechanism for avoiding this problem. The compiler/typechecker uses various functions and constants that are not built in to the language: for instance rewriting requires PropositionalEquality and its refl constructor, and desugaring numerals requires knowledge of the natural number type and the zero and suc constructors.

All of these are made known to the Agda system in the standard library with a pragma:

{-# LANGUAGE BUILTIN REFL refl #-}
{-# LANGUAGE BUILTIN ZERO zero #-}

etc.

It's then possible to completely throw out the standard library and replace it with one of your own by using these pragmas to tell Agda to use your definitions instead.

comment:21 Changed 3 years ago by nomeata

Nice finding. But what is their scope? Do they leak to other modules like instance declarations? What if there are conflicts?

comment:22 Changed 2 years ago by hvr

Owner: ekmett deleted
Resolution: fixed
Status: closednew

comment:23 Changed 2 years ago by hvr

Resolution: wontfix
Status: newclosed

(it's not really fixed, more like wontfix for the meantime IMO)

comment:24 Changed 23 months ago by Lemming

I am also one of these programmers who care about portability. How about creating a Haskell 2010 report with an addendum? It would maintain the language part of Haskell 2010 but add the modules Control.Applicative, Data.Monoid, Data.Foldable, Data.Traversable. I have several packages that use very basic functionality and I would like to show this by importing haskell2010 or haskell2010add. Alternatively, the split-base project would serve my needs.

Note: See TracTickets for help on using tickets.