|
|
|
|
|
There are several examples where one would like access to desugared typeclass dictionary types. For example, creating new instances at runtime like in [ reflection](https://www.fpcomplete.com/user/thoughtpolice/using-reflection#turning-up-the-magic-to-over-9000). Indeed, access to dictionary constructors would probably make the reflection package much simpler and less spooky.
|
|
|
## Base proposal
|
|
|
|
|
|
|
|
|
Currently, typeclass dictionary constructors are [ prepended with "D:"](https://github.com/ghc/ghc/blob/4d5f83a8dcf1f1125863a8fb4f847d78766f1617/compiler/basicTypes/OccName.hs#L615), ensuring that no source level Haskell code can access them.
|
|
|
Expose the constructor of the dictionary datatype created by desugaring typeclasses. This seems unlikely to require any further changes - local type-based instances are still not allowed, but arbitrary dictionaries can be constructed and passed manually. This is possible /already/, but it requires creating a seperate type which mimics the structure of the desugared dictionary. No inference changes are required, no new syntax.
|
|
|
|
|
|
### Additional proposals
|
|
|
|
|
|
This proposal is about allowing source level access to the dictionary constructors. Note that it is not about local instances: There would be no way to override the type-based dictionary usage, just like the present. Instead, all it would allow is something like the following:
|
|
|
- Integrate the *reflection* and parts of the *constraints* library into the core class libraries, and this: (code from [ here](https://www.fpcomplete.com/user/thoughtpolice/using-reflection))
|
|
|
|
|
|
```wiki
|
|
|
class Monoid a where
|
|
|
mempty :: a
|
|
|
mconcat :: a -> a -> a
|
|
|
newtype Lift (p :: * -> Constraint) (a :: *) (s :: *) = Lift { lower :: a }
|
|
|
|
|
|
class ReifiableConstraint p where
|
|
|
reifiedIns :: Reifies s (p a) :- p (Lift p a s)
|
|
|
|
|
|
--allows access to the following type in the same module as the class declaration
|
|
|
|
|
|
data Monoid a = Monoid { mempty :: a, mconcat :: a -> a -> a} -- :: Constraint
|
|
|
with :: p a -> (forall s. Reifies s (p a) => Lift p a s) -> a
|
|
|
with d v = reify d (lower . asProxyOf v)
|
|
|
where
|
|
|
asProxyOf :: f s -> Proxy s -> f s
|
|
|
asProxyOf x _ = x
|
|
|
|
|
|
using :: forall p a. ReifiableConstraint p => p a -> (p a => a) -> a
|
|
|
using d m = reify d $ \(_ :: Proxy s) ->
|
|
|
let replaceProof :: Reifies s (p a) :- p a
|
|
|
replaceProof = trans proof reifiedIns
|
|
|
where proof = unsafeCoerceConstraint :: p (Lift p a s) :- p a
|
|
|
in m \\ replaceProof
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
If the reflection package was merged into base, ideally it would also generate the instances to allow reification to be used like so (from the article):
|
|
|
Example usage of this:
|
|
|
|
|
|
```wiki
|
|
|
--These two instances can and should be automatically created by the compiler eventually, but it isn't strictly necessary
|
|
|
instance ReifiableConstraint Monoid where
|
|
|
reifiedIns = Sub Dict
|
|
|
|
|
|
instance Reifies s (Monoid a) => Monoid (Lift Monoid a s) where
|
|
|
mappend a b = Lift $ mappend (reflect a) (lower a) (lower b)
|
|
|
mempty = a where a = Lift $ mempty (reflect a)
|
|
|
|
|
|
--now to use it
|
|
|
|
|
|
using (Monoid (+) 0) $ mempty <> 10 <> 12 -- evaluates to 22
|
|
|
using (Monoid (*) 1) $ mempty <> 10 <> 12 -- evaluates to 120
|
|
|
```
|
|
|
|
|
|
## What this proposal is NOT
|
|
|
|
|
|
|
|
|
It is not a proposal for local typeclass instances based on type. That is, this proposal allows easier access to creating dictionary terms, but not not in types. This is basically just removing the need to create identical data structures as a workaround.
|
|
|
|
|
|
|
|
|
It is not a proposal for any new syntax or runtime behaviour or types.
|
|
|
|
|
|
## Rationale
|
|
|
|
|
|
|
|
|
There are several examples where one would like access to desugared typeclass dictionary types. For example, creating new instances at runtime like in [ reflection](https://www.fpcomplete.com/user/thoughtpolice/using-reflection#turning-up-the-magic-to-over-9000). Indeed, access to dictionary constructors would probably make the reflection package much simpler and less spooky.
|
|
|
|
|
|
|
|
|
Currently, typeclass dictionary constructors are [ prepended with "D:"](https://github.com/ghc/ghc/blob/4d5f83a8dcf1f1125863a8fb4f847d78766f1617/compiler/basicTypes/OccName.hs#L615), ensuring that no source level Haskell code can access them.
|
|
|
|
|
|
|
|
|
This proposal is about allowing source level access to the dictionary constructors. Note that it is not about local instances: There would be no way to override the type-based dictionary usage, just like the present.
|
|
|
|
|
|
|
|
|
It would allow, for example, far greater ease of implementation of dictionary-based methods, such as is often needed in constructive category theory. Otherwise, it is [ messy as hell](https://hackage.haskell.org/package/data-category-0.6.1/docs/Data-Category-Monoidal.html#t:MonoidObject). Additionally, this kept coming up while working on the monoidal category proposal for replacing arrow notation; it was a huge barrier to a nice interface/api.
|
|
|
|
|
|
## Implementation
|
|
|
|
|
|
|
|
|
The first shot at allowing access to the constructors is to simply replace the string "D:" with "".
|
|
|
|
|
|
|
|
|
Doing so reveals two things: 1) In ghci, it still does not work - the parser catches "Monoid undefined undefined undefined" with "Not in scope: data constructor Monoid"
|
|
|
Doing so reveals two things:
|
|
|
|
|
|
|
|
|
1) It still does not work - the parser catches "Monoid undefined undefined undefined" with "Not in scope: data constructor Monoid". Is this because it's getting caught in the parser?
|
|
|
2)
|
|
|
|
|
|
```wiki
|
... | ... | @@ -45,4 +94,7 @@ testsuite/tests/indexed-types/should_compile/Deriving.hs:8:1: Warning: |
|
|
|
|
|
/tmp/ghc13400_0/ghc13400_2.s:811:0:
|
|
|
Error: symbol `ShouldCompile_C_static_info' is already defined
|
|
|
``` |
|
|
\ No newline at end of file |
|
|
```
|
|
|
|
|
|
|
|
|
This goes away when the "D:" is replaced with something like "MkDict" instead of a blank. |