tcInferRho

Richard Eisenberg eir at cis.upenn.edu
Tue Jul 22 12:21:51 UTC 2014


OK -- that all makes sense.

But why does it actually work, I wonder? It seems that to get the behavior that you describe below, and the behavior that we see in practice, a unification variable *does* have to unify with a non-tau-type, like (forall a. a -> a) -> Int. But doesn't defer_me in TcUnify.checkTauTvUpdate prevent such a thing from happening?

To learn more, I tried compiling this code:

> f :: Bool -> Bool -> (forall a. a -> a) -> ()
> f = undefined
> 
> g = (True `f` False) id

I use infix application to avoid tcInferRho.

With -ddump-tc-trace -dppr-debug, I see the following bit:

> Scratch.hs:18:6:
>     u_tys 
>       untch 0
>       (forall a{tv apE} [sk]. a{tv apE} [sk] -> a{tv apE} [sk]) -> ()
>       ~
>       t_aHO{tv} [tau[0]]
>       a type equality (forall a{tv apE} [sk].
>                        a{tv apE} [sk] -> a{tv apE} [sk])
>                       -> ()
>                       ~
>                       t_aHO{tv} [tau[0]]
> Scratch.hs:18:6:
>     writeMetaTyVar
>       t_aHO{tv} [tau[0]] := (forall a{tv apE} [sk].
>                              a{tv apE} [sk] -> a{tv apE} [sk])
>                             -> ()
> 

What's very strange to me here is that we see t_aHO, a **tau** type, being rewritten to a poly-type. I could clearly throw in more printing statements to see what is going on, but I wanted to check if this looks strange to you, too.

Thanks,
Richard

On Jul 22, 2014, at 6:28 AM, Simon Peyton Jones <simonpj at microsoft.com> wrote:

> Richard
> 
> You are right; there is something squishy here.
> 
> The original idea was that a unification variable only stands for a *monotype* (with no for-alls).  But our basic story for the type inference engine is
> 	tcExpr :: HsExpr -> TcType -> TcM HsExpr'
> which checks that the expression has the given expected type. To do inference we pass in a unification variable as the "expected type".  BUT if the expression actually has a type like (forall a. a->a) -> Int, then the unification variable clearly isn't being unified with a monotype.  There are a couple of places where we must "zonk" the expected type, after calling tcExpr, to expose the foralls.  A major example is TcExpr.tcInferFun.
> 
> I say this is squishy because *in principle* we could replace every unification with generating an equality constraint, for later solving.  (This does often happen, see TcUnify.uType_defer.)  BUT if we generate an equality constraint, the zonking won't work, and the foralls won't be exposed early enough.  I wish that the story here was more solid.
> 
> The original idea of tcInferRho was to have some special cases that did not rely on this squishy "unify with polytype" story. It had a number of special cases, perhaps not enough as you observe.  But it does look as if the original goal (which I think was to deal with function applications) doesn't even use it -- it uses tcInferFun instead.
> 
> So I think you may be right: tcInferRho may not be important.  There is a perhaps-significant efficiency question though: it avoids allocating an unifying a fresh unification variable each time.
> 
> Simon
> 
> | -----Original Message-----
> | From: Richard Eisenberg [mailto:eir at cis.upenn.edu]
> | Sent: 18 July 2014 22:00
> | To: Simon Peyton Jones
> | Subject: Re: tcInferRho
> | 
> | I thought as much, but I can't seem to tickle the bug. For example:
> | 
> | > {-# LANGUAGE RankNTypes #-}
> | >
> | > f :: Int -> Bool -> (forall a. a -> a) -> Int
> | > f = undefined
> | >
> | > x = (3 `f` True)
> | >
> | 
> | 
> | GHCi tells me that x's type is `x :: (forall a. a -> a) -> Int`, as we
> | would hope. If we were somehow losing the higher-rank polymorphism
> | without tcInferRho, then I would expect something like `(3 `f` True) $
> | not)` to succeed (or behave bizarrely), but we get a very sensible type
> | error
> | 
> |     Couldn't match type 'a' with 'Bool'
> |       'a' is a rigid type variable bound by
> |           a type expected by the context: a -> a
> |           at /Users/rae/temp/Bug.hs:6:5
> |     Expected type: a -> a
> |       Actual type: Bool -> Bool
> |     In the second argument of '($)', namely 'not'
> |     In the expression: (3 `f` True) $ not
> | 
> | So, instead of just adding more cases, I wonder if we can't *remove*
> | cases, as it seems that the gears turn fine without this function. This
> | continues to surprise me, but it's what the evidence indicates. Can you
> | make any sense of this?
> | 
> | Thanks,
> | Richard
> | 
> | 
> | On Jul 18, 2014, at 12:49 PM, Simon Peyton Jones <simonpj at microsoft.com>
> | wrote:
> | 
> | > You're right, its' an omission.  The reason for the special case is
> | described in the comment on tcInferRho.  Adding OpApp would be a Good
> | Thing.  A bit tiresome because we'd need to pass to tcInferApp the
> | function to use to reconstruct the result HsExpr (currently foldl
> | mkHsApp, in tcInferApp), so that in the OpApp case it'd reconstruct an
> | OpApp.
> | >
> | > Go ahead and do this if you like
> | >
> | > S
> | >
> | > | -----Original Message-----
> | > | From: Richard Eisenberg [mailto:eir at cis.upenn.edu]
> | > | Sent: 17 July 2014 18:48
> | > | To: Simon Peyton Jones
> | > | Subject: tcInferRho
> | > |
> | > | Hi Simon,
> | > |
> | > | I'm in the process of rejiggering the functions in TcHsType to be
> | more
> | > | like those in TcExpr, in order to handle the richer type/kind
> | language
> | > | of my branch.
> | > |
> | > | I have a question about tcInferRho (TcExpr.lhs:115). It calls
> | > | tcInfExpr, which handles three special cases of HsExpr, before
> | > | deferring to tcExpr. The three cases are HsVar, HsPar, and HsApp.
> | > | What's odd about this is that there are other cases that seem to
> | belong
> | > | in this group, like OpApp. After all, (x + y) and ((+) x y) should
> | > | behave the same in all circumstances, right? I can't find a way to
> | > | tickle the omission here, so there may not be a bug, but it certainly
> | > | is a little strange. Can you shed any light?
> | > |
> | > | Thanks!
> | > | Richard
> | >
> 
> 



More information about the ghc-devs mailing list