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

Support monads #184

Closed
3 tasks done
goldfirere opened this issue May 31, 2017 · 7 comments
Closed
3 tasks done

Support monads #184

goldfirere opened this issue May 31, 2017 · 7 comments

Comments

@goldfirere
Copy link
Owner

goldfirere commented May 31, 2017

We're surprisingly close to being able to support monads (and, with them, list comprehensions). Singletonizing the basic class definitions works. But there's danger on the horizon.

The problem has all to do with CUSKs. As Note [CUSKification] in Promote describes, we have little control over when GHC infers a CUSK. And this causes havoc when we want GHC to infer the kind of higher-kinded type variables. Specifically, the PFunctor class has a CUSK, and so the user needs to write class Functor (f :: * -> *). Putting in the kind annotations here isn't so, so terrible.

What's worse is that we run into similar problems elsewhere. I haven't tracked down the precise details, but compiling Base.hs on the monads branch led to an error where a defunctionalization symbol has a CUSK, and thus inferring that a kind variable should be higher-kinded fails.

Short of fixing CUSKs in GHC, the solution might be to emit GADT-style declarations of defunctionalization symbols instead of H98-style. This would allow us finer control of whether we have a CUSK. (Recall that, with TypeInType, all kind variables must be explicitly quantified in order to have a CUSK. So we just won't do that.) This is tantalizingly close. But I'm not going to get there tonight.

Checklist:

@RyanGlScott
Copy link
Collaborator

If we're adding an Applicative class as part of this work, then we'll need this instance:

instance Monoid a => Applicative ((,) a)

But currently, we don't have a Monoid (or Semigroup) class within singletons. Adopting GHC 8.4 is good timing for this, now that Semigroup has become a superclass of Monoid, making adding the two in tandem much easier.

@RyanGlScott
Copy link
Collaborator

Also, if we're going to be adding Control.Monad at some point, then we'll need to implement Foldable/Traversable as well, since it's required by the function:

mapM :: (Traversable t, Monad m) => (a -> m b) -> t a -> m (t b)

Which is re-exported from Control.Monad.

Of course, Foldable and Traversable might suffer from the same higher-kinded, defunctionalization-related CUSK issues mentioned in #184 (comment), so perhaps that's out-of-reach for the time being. But one thing we can do in preparation for their eventual arrival is to add the Identity and Const newtypes:

newtype Identity a = Identity { runIdentity :: a }
newtype Const a (b :: Type) = Const { getConst :: a } -- Kind-restricted

Why would we need these? Because they're used in two definitions in Data.Traversable:

fmapDefault :: forall t a b . Traversable t => (a -> b) -> t a -> t b
fmapDefault f = runIdentity . traverse (Identity . f)

foldMapDefault :: forall t m a . (Traversable t, Monoid m) => (a -> m) -> t a -> m
foldMapDefault f = getConst . traverse (Const . f)

(Plus, Const is re-exported from Control.Applicative.)

As far as I know, nothing is blocking us from adding Identity or Const, so that might be good intermediate step.

@RyanGlScott
Copy link
Collaborator

RyanGlScott commented Mar 3, 2018

Also, I figured out what CUSK issue you're referring to. Here's a minimized example:

{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeInType #-}
{-# LANGUAGE TypeOperators #-}
{-# OPTIONS_GHC -ddump-splices #-}
module Bug where

import Data.Kind
import Data.Singletons.TH

$(singletons
    [d| class App (f :: * -> *) where
          (**>) :: f a -> f b -> f b
      |])

This generates the following defunctionalization data type:

data (:**>$$) (l1 :: f a) (l2 :: TyFun (f b) (f b)) where ...

About which GHC complains:

Bug2.hs:13:1: error:
    You have written a *complete user-suppled kind signature*,
    but the following variable is undetermined: k0 :: *
    Perhaps add a kind signature.
    Inferred kinds of user-written variables:
      a :: k0
      f :: k0 -> *
      b :: k0
      l1 :: f a
      l2 :: TyFun (f b) (f b)
   |
13 | data (:**>$$) (l1 :: f a) (l2 :: TyFun (f b) (f b)) where
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...

It turns out, though, that there is a way to hack around this:

$(singletons
    [d| class App (f :: * -> *) where
          (**>) :: (f :: * -> *) a -> f b -> f b
      |])

That's somewhat unsightly, but it's a serviceable workaround.

RyanGlScott added a commit that referenced this issue Mar 4, 2018
RyanGlScott added a commit that referenced this issue Apr 2, 2018
RyanGlScott added a commit that referenced this issue Apr 6, 2018
@RyanGlScott
Copy link
Collaborator

Pull request #314 adds the Functor, Applicative, and Monad classes.

I'll work on adding Foldable and Traversable (and thus Const and Identity) separately.

@RyanGlScott
Copy link
Collaborator

Although Monad and its immediate immediate family have been implemented, there are some remaining loose ends to tie up.

@RyanGlScott RyanGlScott reopened this Jun 5, 2018
RyanGlScott added a commit that referenced this issue Jun 6, 2018
…n and TypeInType]

I discovered this buglet when trying to single a polykinded version of
the Const data type (for #184), which critically relies on this when
defunctionalizing its Enum instance.
RyanGlScott added a commit that referenced this issue Jun 12, 2018
This completes the `Data.Singletons.Prelude.*` changes necessary to
support `Monad` and friends. This:

* Adds the appropriate modules for the `Foldable` and `Traversable`
  classes, as well as the `Identity` and `Const` newtypes.
* Uncomments various things in
  `Data.Singletons.Prelude.{Applicative,Monad}` that couldn't be
  supported before due to the lack of the classes in the previous
  bullet points.
* Reexports the appropriate `Foldable`/`Traversable` functions from
  `Data.{Promotion,Singletons}.Prelude.List` to mirror what
  `Data.List` does. This required some reorganization of internal
  modules, but was otherwise straightforward.

Checks off the second bullet point in #184.
@RyanGlScott
Copy link
Collaborator

Pull request #337 is about the second bullet point (Foldable, Traversable, Const, and Identity).

RyanGlScott added a commit that referenced this issue Jun 14, 2018
* Promote and single Foldable, Traversable, Const, and Identity

This completes the `Data.Singletons.Prelude.*` changes necessary to
support `Monad` and friends. This:

* Adds the appropriate modules for the `Foldable` and `Traversable`
  classes, as well as the `Identity` and `Const` newtypes.
* Uncomments various things in
  `Data.Singletons.Prelude.{Applicative,Monad}` that couldn't be
  supported before due to the lack of the classes in the previous
  bullet points.
* Reexports the appropriate `Foldable`/`Traversable` functions from
  `Data.{Promotion,Singletons}.Prelude.List` to mirror what
  `Data.List` does. This required some reorganization of internal
  modules, but was otherwise straightforward.

Checks off the second bullet point in #184.

* Use list comprehensions in a couple more places
RyanGlScott added a commit that referenced this issue Jun 21, 2018
@RyanGlScott
Copy link
Collaborator

Finally, #344 implements the last bullet point (DeriveFunctor, DeriveFoldable, and DeriveTraversable).

RyanGlScott added a commit that referenced this issue Jun 21, 2018
RyanGlScott added a commit that referenced this issue Jun 21, 2018
* Support deriving Functor, Foldable, and Traversable

Fixes #184 for good.

* Use a map from stock classes to their decs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants