Hello cafe,
I have a question wrt. to GADTs and type families in GHC (7.6.1).
I'd like to transform a value of an ADT to a GADT. Suppose I have the
simple expression language
> data Exp = Lit Int > | Succ Exp > | IsZero Exp > | If Exp Exp Exp
and the GADT
> data Term t where > TLit :: Int -> Term Int > TSucc :: Term Int ->
Term Int > TIsZero :: Term Int -> Term Bool > TIf :: Term Bool -> Term
ty -> Term ty -> Term ty
that encodes the typing rules.
Now, I'd like to have a function
> typecheck :: Exp -> Maybe (Term t) > typecheck exp = <...>
that returns the GADT value corresponding to `exp' if `exp' is type
correct.
I found a solution at
http://okmij.org/ftp/tagless-final/TypecheckedDSLTH.hs but this has as
type (slightly adapted)
> typecheck :: Exp -> Maybe TypedTerm
with
> data TypedTerm = forall ty. (Typ ty) (Term ty) > data Typ ty =
> TInt
Int | TBool Bool
That is, the GADT value is hidden inside the existential and cannot be
unpacked. Therefore, I cannot write a type preserving transformation
function like
> transform :: Term t -> Term t
that gets the result of the `typecheck' function as input.
The solution mentioned above uses Template Haskell to extract the
`Term t' type from the existential package and argues that type errors
cannot occur during splicing.
Is there a possibility to avoid the existential and hence Template
Haskell?
Of course, the result type of typecheck depends on the type and type
correctness of its input.
My idea was to express this dependency by parameterizing `Exp' and
using a type family `ExpType' like:
> typecheck :: Exp e -> Maybe (Term (ExpType e)) > typecheck (ELit
> i)
= Just (TLit i) > typecheck (ESucc exp1) = case typecheck exp1 of >
Nothing -> Nothing > Just t -> Just (TSucc t) > <...>
with
> data TEXP = L | S TEXP | IZ TEXP | I TEXP TEXP TEXP -- datakind >
> >
data Exp (e::TEXP) where > ELit :: Int -> Exp L > ESucc :: Exp e1 ->
Exp (S e1) > EIsZero :: Exp e1 -> Exp (IZ e1) > EIf :: Exp e1 -> Exp
e2 -> Exp e3 -> Exp (I e1 e2 e3)
It seems to me that `ExpType' then would be a reification of the type
checker for `Exp' at the type level. But I did not know how to define
it. Does it make sense at all? Is it possible in GHC?
All the examples on the net I looked at either start with the GADT
right away or use Template Haskell at some point. So, perhaps this
`typecheck' function is not possible to write in GHC Haskell.
I very much appreciate any hints and explanations on this.
Best regards,
Florian
- --
Florian Lorenzen
Technische Universität Berlin
Fakultät IV - Elektrotechnik und Informatik
Übersetzerbau und Programmiersprachen
Sekr. TEL12-2, Ernst-Reuter-Platz 7, D-10587 Berlin
Tel.: +49 (30) 314-24618
E-Mail: florian....@tu-berlin.de
WWW: http://www.user.tu-berlin.de/florenz/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://www.enigmail.net/
iEYEARECAAYFAlBTCr8ACgkQvjzICpVvX7ZfTgCeOPflPtaEW/w1McjYWheaRaqq
oUQAnRXSrGP3se+3oiI3nnd+B/rK8yx8
=X1hR
-----END PGP SIGNATURE-----
_______________________________________________
Haskell-Cafe mailing list
Haskel...@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
I'd like to transform a value of an ADT to a GADT. Suppose I have the
simple expression language
> data Exp = Lit Int > | Succ Exp > | IsZero Exp > | If Exp Exp Exp
and the GADT
> data Term t where > TLit :: Int -> Term Int > TSucc :: Term Int ->
Term Int > TIsZero :: Term Int -> Term Bool > TIf :: Term Bool -> Term
ty -> Term ty -> Term ty
that encodes the typing rules.
Now, I'd like to have a function
> typecheck :: Exp -> Maybe (Term t) > typecheck exp = <...>
that returns the GADT value corresponding to `exp' if `exp' is type
correct.
Dear Sean,
thanks for your solution. It in the documentation of unsafeCoerce it
says: "It [unsafeCoerce] is generally used when you want to write a
program that you know is well-typed, but where Haskell's type system
is not expressive enough to prove that it is well typed."
May I conclude that the (GHC) Haskell type system is not powerful
enough to type such a typecheck function?
Best regards,
Florian
- --
Florian Lorenzen
Technische Universität Berlin
Fakultät IV - Elektrotechnik und Informatik
Übersetzerbau und Programmiersprachen
Sekr. TEL12-2, Ernst-Reuter-Platz 7, D-10587 Berlin
Tel.: +49 (30) 314-24618
E-Mail: florian....@tu-berlin.de
WWW: http://www.user.tu-berlin.de/florenz/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://www.enigmail.net/
iEYEARECAAYFAlBTH10ACgkQvjzICpVvX7ZIVACdEPtbEHbVeQcdgzQTanVkpeKq
8QsAn3b774JsVyMMVc1lIN2rFlTVheQD
=zgOc
I don't think this is safe. What will happen if you evaluate
typecheck (Lit 1) :: Maybe (Term Bool)
Thanks Oleg for this elaboration. I'm now happy with the solution
involving an existential. I first did not realize that I still could
apply functions of type `Term t -> Term t` as soon as I open the package.
On 09/15/2012 01:02 PM, ol...@okmij.org wrote:
> Florian Lorenzen wrote: Chances are that you wanted the following
>
> typecheck :: {e:Exp} -> Result e where Result e has the type (Just
> (Term t)) (with some t dependent on e) if e is typeable, and
> Nothing otherwise. But this is a dependent function type
> (Pi-type). No wonder we have to go through contortions like
> Template Haskell to emulate dependent types in Haskell. Haskell was
> not designed to be a dependently-typed language.
Yes, this is what I was looking for. I know, Haskell is not
dependently typed. But since many dependently typed idioms (like
printf) can already be expressed using the GHC Haskell type system, I
was wondering if this one was also possible.
Best regards,
Florian
- --
Florian Lorenzen
Technische Universität Berlin
Fakultät IV - Elektrotechnik und Informatik
Übersetzerbau und Programmiersprachen
Sekr. TEL12-2, Ernst-Reuter-Platz 7, D-10587 Berlin
Tel.: +49 (30) 314-24618
E-Mail: florian....@tu-berlin.de
WWW: http://www.user.tu-berlin.de/florenz/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://www.enigmail.net/
iEYEARECAAYFAlBW2YIACgkQvjzICpVvX7alFwCgkS5Gq2CfJqxX5ZV2TJQslSDn
a9IAoJCj3HY5J8kU5T1HcCJGDFbUaLrc
=G/Zf
-----END PGP SIGNATURE-----
Thanks Erik. This made the issue clear to me.
Best regards,
Florian
On 09/14/2012 03:22 PM, Erik Hesselink wrote:
> On Fri, Sep 14, 2012 at 2:27 PM, Erik Hesselink
> <hess...@gmail.com> wrote:
>> In general, I think you have to work inside an existential. So
>> you hide the type of the parsed Term inside an existential. If
>> you want to apply functions to this Term, you unpack, call the
>> function, and repack.
>
> Maybe I should expand what I mean by this. Let's say you have:
>
> data SomeTerm where SomeTerm :: Term a -> SomeTerm
>
> Your typecheck function goes:
>
> typecheck :: Exp -> SomeTerm
>
> and you want to apply:
>
> transform :: Term t -> Term t
>
> You should do something like:
>
> f (SomeTerm t) = SomeTerm (transform t)
>
> Or, more generally:
>
> onSomeTerm :: (forall t. Term t -> Term t) -> SomeTerm -> SomeTerm
> onSomeTerm f (SomeTerm t) = SomeTerm (f t)
>
> Erik
>
- --
Florian Lorenzen
Technische Universität Berlin
Fakultät IV - Elektrotechnik und Informatik
Übersetzerbau und Programmiersprachen
Sekr. TEL12-2, Ernst-Reuter-Platz 7, D-10587 Berlin
Tel.: +49 (30) 314-24618
E-Mail: florian....@tu-berlin.de
WWW: http://www.user.tu-berlin.de/florenz/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://www.enigmail.net/
iEYEARECAAYFAlBW2bgACgkQvjzICpVvX7Zr3QCfbIqkX9WqM69NLyk98aqyNcYe
RrUAniGndhj9OTl9XIoUBC/hoBI1lwML
=hReY
-----END PGP SIGNATURE-----
José, it occurs to me that with this solution, I always have to
prescribe the type as in
> tc (Succ (Lit 5)) :: Maybe (Term Int)
Otherwise, I obtain the message
Ambiguous type variable `a0' in the constraint:
(Tc a0) arising from a use of `tc'
But as Oleg already pointed out, I want to have a value `Just term ::
Maybe (Term t)' if the input is well-typed for some type which I don't
know.
Best regards,
Florian
On 09/16/2012 01:45 PM, José Pedro Magalhães wrote:
> Hi Florian,
>
> Will this do?
>
> class Tc a where tc :: Exp -> Maybe (Term a)
>
> instance Tc Int where tc (Lit i) = return (TLit i) tc (Succ i)
> = tc i >>= return . TSucc tc (IsZero i) = Nothing tc e
> = tcIf e
>
> instance Tc Bool where tc (Lit i) = Nothing tc (Succ i) =
> Nothing tc (IsZero i) = tc i >>= return . TIsZero tc e
> = tcIf e
>
> tcIf :: (Tc a) => Exp -> Maybe (Term a) tcIf (If c e1 e2) = do c'
> <- tc c e1' <- tc e1 e2' <- tc e2 return (TIf c' e1' e2')
>
>
> Cheers, Pedro
>
> On Fri, Sep 14, 2012 at 11:45 AM, Florian Lorenzen
> <florian....@tu-berlin.de
> _______________________________________________ Haskell-Cafe
> mailing list Haskel...@haskell.org
> <mailto:Haskel...@haskell.org>
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>
>
- --
Florian Lorenzen
Technische Universität Berlin
Fakultät IV - Elektrotechnik und Informatik
Übersetzerbau und Programmiersprachen
Sekr. TEL12-2, Ernst-Reuter-Platz 7, D-10587 Berlin
Tel.: +49 (30) 314-24618
E-Mail: florian....@tu-berlin.de
WWW: http://www.user.tu-berlin.de/florenz/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://www.enigmail.net/
iEYEARECAAYFAlBW24UACgkQvjzICpVvX7bWZACfVWRiNrJVl/ue5sk/AFsAK36m
zeUAniWoGahDymxAqkBK6JWQ5jNzDR6f
=FRcI