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

Make singling preserve type variable order in type signatures #408

Merged
merged 1 commit into from
Sep 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ Changelog for singletons project
next
----
* Require GHC 8.10.
* `singletons` now does a much better job of preserving the order of type
variables when singling the type signatures of top-level functions and data
constructors. See the `Support for TypeApplications` section of the `README`
for more details.
* `singletons` now does a more much thorough job of rejecting higher-rank types
during promotion or singling, as `singletons` cannot support them.
(Previously, `singletons` would sometimes accept them, often changing rank-2
Expand Down
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,42 @@ mechanism will not promote `TypeRep` to `*`.
of types with which to work. See the Haddock documentation for the function
`singletonStar` for more info.

Support for `TypeApplications`
------------------------------

`singletons` currently cannot handle promoting or singling code that uses
`TypeApplications` syntax, so `singletons` will simply drop any visible type
applications. For example, `id @Bool True` will be promoted to `Id True` and
singled to `sId STrue`. See
[#378](https://github.com/goldfirere/singletons/issues/378) for a discussion
of how `singletons` may support `TypeApplications` in the future.

On the other hand, `singletons` does make an effort to preserve the order of
type variables when singling type signatures. For example, this type signature:

```haskell
const2 :: forall b a. a -> b -> a
```

Will single to the following:

```haskell
sConst2 :: forall b a (x :: a) (y :: a). Sing x -> Sing y -> Sing (Const x y)
```

Therefore, writing `const2 @T1 @T2` works just as well as writing
`sConst2 @T1 @T2`, since the type signatures for `const2` and `sConst2` both
begin with `forall b a.`, in that order. Again, it is worth emphasizing that
the TH machinery does not support singling `const2 @T1 @T2` directly, but you
can write the type applications by hand if you so choose.

It is not yet guaranteed that promotion preserves the order of type variables.
For instance, if one writes `const @T1 @T2`, then one would have to write
`Const @T2 @T1` at the kind level (and similarly for `Const`'s
defunctionalization symbols). See
[#378](https://github.com/goldfirere/singletons/issues/378) for a discussion
of how this may be fixed in the future.

Known bugs
----------

Expand Down
22 changes: 11 additions & 11 deletions src/Data/Singletons/Promote/Monad.hs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type LetExpansions = OMap Name DType -- from **term-level** name
data PrEnv =
PrEnv { pr_lambda_bound :: OMap Name Name
, pr_let_bound :: LetExpansions
, pr_forall_bound :: OSet Name -- See Note [Explicitly quantifying kinds variables]
, pr_forall_bound :: OSet Name -- See Note [Explicitly binding kind variables]
, pr_local_decls :: [Dec]
}

Expand Down Expand Up @@ -129,17 +129,17 @@ promoteMDecs locals thing = do

{-
Note [Explicitly binding kind variables]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We want to ensure that when we single type signatures for functions, we should
explicitly quantify every kind variable bound by a forall. For example, if we
were to single the identity function:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
We want to ensure that when we single type signatures for functions and data
constructors, we should explicitly quantify every kind variable bound by a
forall. For example, if we were to single the identity function:

identity :: forall a. a -> a
identity x = x

We want the final result to be:

sIdentity :: forall a (x :: a). Sing x -> Sing (Identity x)
sIdentity :: forall a (x :: a). Sing x -> Sing (Identity x :: a)
sIdentity sX = sX

Accomplishing this takes a bit of care during promotion. When promoting a
Expand All @@ -160,28 +160,28 @@ consider this more complicated example:

When singling, we would eventually end up in this spot:

sF :: forall a (x :: a). Sing a -> Sing (F a)
sF :: forall a (x :: a). Sing a -> Sing (F a :: a)
sF = sG
where
sG :: _
sG x = x

We must make sure /not/ to fill in the following type for _:

sF :: forall a (x :: a). Sing a -> Sing (F a)
sF :: forall a (x :: a). Sing a -> Sing (F a :: a)
sF = sG
where
sG :: forall a (y :: a). Sing a -> Sing (G a)
sG :: forall a (y :: a). Sing a -> Sing (G a :: a)
sG x = x

This would be incorrect, as the `a` bound by sF /must/ be the same one used in
sG, as per the scoping of the original `f` function. Thus, we ensure that the
bound variables from `f` are put into lde_bound_kvs when promoting `g` so
that we subtract out `a` and are left with the correct result:

sF :: forall a (x :: a). Sing a -> Sing (F a)
sF :: forall a (x :: a). Sing a -> Sing (F a :: a)
sF = sG
where
sG :: forall (y :: a). Sing a -> Sing (G a)
sG :: forall (y :: a). Sing a -> Sing (G a :: a)
sG x = x
-}
29 changes: 12 additions & 17 deletions src/Data/Singletons/Single/Data.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ Singletonizes constructors.
module Data.Singletons.Single.Data where

import Language.Haskell.TH.Desugar
import Language.Haskell.TH.Desugar.OSet (OSet)
import Language.Haskell.TH.Syntax
import Data.Singletons.Single.Defun
import Data.Singletons.Single.Monad
Expand All @@ -22,7 +21,6 @@ import Data.Singletons.Util
import Data.Singletons.Names
import Data.Singletons.Syntax
import Control.Monad
import Data.Foldable

-- We wish to consider the promotion of "Rep" to be *
-- not a promoted data constructor.
Expand Down Expand Up @@ -129,12 +127,12 @@ singDataD (DataDecl name tvbs ctors) = do
pure $ DClause [DVarP x]
$ DConE someSingDataName `DAppE` DCaseE (DVarE x) []

-- refine a constructor.
-- Single a constructor.
singCtor :: Name -> DCon -> SgM DCon
-- polymorphic constructors are handled just
-- like monomorphic ones -- the polymorphism in
-- the kind is automatic
singCtor dataName (DCon _tvbs cxt name fields rty)
singCtor dataName (DCon con_tvbs cxt name fields rty)
| not (null cxt)
= fail "Singling of constrained constructors not yet supported"
| otherwise
Expand All @@ -144,13 +142,13 @@ singCtor dataName (DCon _tvbs cxt name fields rty)
sCon = DConE sName
pCon = DConT name
indexNames <- mapM (const $ qNewName "n") types
let indices = map DVarT indexNames
kinds <- mapM promoteType types
let bound_kvs = foldMap fvDType kinds
args <- zipWithM (buildArgType bound_kvs) types indices
rty' <- promoteType rty
let tvbs = map DPlainTV (toList bound_kvs) ++ zipWith DKindedTV indexNames kinds
let indices = map DVarT indexNames
kindedIndices = zipWith DSigT indices kinds
args = map (DAppT singFamily) indices
kvbs = singTypeKVBs con_tvbs kinds [] rty' mempty
all_tvbs = kvbs ++ zipWith DKindedTV indexNames kinds

-- SingI instance for data constructor
emitDecs
Expand All @@ -172,12 +170,9 @@ singCtor dataName (DCon _tvbs cxt name fields rty)
DRecC [ (singValName field_name, noBang, arg)
| (field_name, _, _) <- rec_fields
| arg <- args ]
return $ DCon tvbs
[]
sName
conFields
(DConT (singTyConName dataName) `DAppT` foldType pCon indices)
where buildArgType :: OSet Name -> DType -> DType -> SgM DType
buildArgType bound_kvs ty index = do
(ty', _, _, _, _, _) <- singType bound_kvs index ty
goldfirere marked this conversation as resolved.
Show resolved Hide resolved
return ty'
return $ DCon all_tvbs [] sName conFields
(DConT (singTyConName dataName) `DAppT`
(foldType pCon indices `DSigT` rty'))
-- Make sure to include an explicit `rty'` kind annotation.
-- See Note [Preserve the order of type variables during singling],
-- wrinkle 3, in D.S.Single.Type.
Loading