
PUBLIC
PUBLIC
Hi,
Thanks! Originally I was going to reply to this saying that my transformation isn't running in CoreM so where do I get that environment from, but then I realized I can just build it from the md_insts field of ModDetails. However, after thinking more about it, I also realized that I shouldn't ever really need to conjure up dictionaries from thin air: the whole reason I am making a specific specialization of an overloaded function is because I found somewhere a call at that type. But then, that call also gives me the dictionary!
Of course at this point, this sounds exactly like what GHC already does in `specProgram`. So maybe I should be able to just use that?
Unfortunately, my initial testing seems to show that even if I run `specBind` manually on my whole-program collected CoreProgram, it doesn't do the work I would expect from it!
In the following example, I have only kept the definitions that are relevant. Before specialisation, I have the following whole-program Core:
(>>=)
:: forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
[GblId[ClassOp], Arity=1, Caf=NoCafRefs, Str=]
(>>=)
= \ (@(m :: * -> *)) (v_sGm [Occ=Once1!] :: Monad m) ->
case v_sGm of
{ C:Monad _ [Occ=Dead] v_sGp [Occ=Once1] _ [Occ=Dead] ->
v_sGp
}
$dm>> :: forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
[GblId, Arity=3, Unf=OtherCon []]
$dm>>
= \ (@(m :: * -> *))
($dMonad [Occ=Once1] :: Monad m)
(@a)
(@b)
(ma [Occ=Once1] :: m a)
(mb [Occ=OnceL1] :: m b) ->
let {
sat_sGQ [Occ=Once1] :: a -> m b
[LclId]
sat_sGQ = \ _ [Occ=Dead] -> mb } in
>>= @m $dMonad @a @b ma sat_sGQ
C:Monad [InlPrag=NOUSERINLINE CONLIKE]
:: forall (m :: * -> *).
Applicative m
-> (forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> Monad m
[GblId[DataCon], Arity=3, Caf=NoCafRefs, Cpr=m1, Unf=OtherCon []]
C:Monad
= \ (@(m :: * -> *))
(eta_B0 [Occ=Once1] :: Applicative m)
(eta_B1 [Occ=Once1] :: forall a b. m a -> (a -> m b) -> m b)
(eta_B2 [Occ=Once1] :: forall a b. m a -> m b -> m b) ->
C:Monad @m eta_B0 eta_B1 eta_B2
$fMonadIO [InlPrag=NOUSERINLINE CONLIKE] :: Monad IO
[GblId[DFunId]]
$fMonadIO = C:Monad @IO $fApplicativeIO bindIO $fMonadIO_$c>>;
$fMonadIO_$c>> [Occ=LoopBreaker]
:: forall a b. IO a -> IO b -> IO b
[GblId]
$fMonadIO_$c>> = \ (@a) (@b) -> $dm>> @IO $fMonadIO @a @b;
sat_sHr :: IO ()
[LclId]
sat_sHr = returnIO @() ()
sat_sHq :: IO ()
[LclId]
sat_sHq = returnIO @() ()
main :: IO ()
[GblId]
main = $fMonadIO_$c>> @() @() sat_sHq sat_sHr
Now I pass this to GHC's `specBind`, but the output is exactly the same as the input! (or it's close enough that I can't spot the difference).
(>>=)
:: forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
[GblId[ClassOp], Arity=1, Caf=NoCafRefs, Str=]
(>>=)
= \ (@(m :: * -> *)) (v_sGm [Occ=Once1!] :: Monad m) ->
case v_sGm of
{ C:Monad _ [Occ=Dead] v_sGp [Occ=Once1] _ [Occ=Dead] ->
v_sGp
}
$dm>> :: forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
[GblId, Arity=3, Unf=OtherCon []]
$dm>>
= \ (@(m :: * -> *))
($dMonad [Occ=Once1] :: Monad m)
(@a)
(@b)
(ma [Occ=Once1] :: m a)
(mb [Occ=OnceL1] :: m b) ->
let {
sat_MHt [Occ=Once1] :: a -> m b
[LclId]
sat_MHt = \ _ [Occ=Dead] -> mb } in
>>= @m $dMonad @a @b ma sat_MHt
C:Monad [InlPrag=NOUSERINLINE CONLIKE]
:: forall (m :: * -> *).
Applicative m
-> (forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> Monad m
[GblId[DataCon], Arity=3, Caf=NoCafRefs, Cpr=m1, Unf=OtherCon []]
C:Monad
= \ (@(m :: * -> *))
(eta_B0 [Occ=Once1] :: Applicative m)
(eta_B1 [Occ=Once1] :: forall a b. m a -> (a -> m b) -> m b)
(eta_B2 [Occ=Once1] :: forall a b. m a -> m b -> m b) ->
C:Monad @m eta_B0 eta_B1 eta_B2
$fMonadIO [InlPrag=NOUSERINLINE CONLIKE] :: Monad IO
[GblId[DFunId]]
$fMonadIO = C:Monad @IO $fApplicativeIO bindIO $fMonadIO_$c>>;
$fMonadIO_$c>> [Occ=LoopBreaker]
:: forall a b. IO a -> IO b -> IO b
[GblId]
$fMonadIO_$c>> = \ (@a) (@b) -> $dm>> @IO $fMonadIO @a @b;
sat_sHr :: IO ()
[LclId]
sat_sHr = returnIO @() ()
sat_sHq :: IO ()
[LclId]
sat_sHq = returnIO @() ()
main :: IO ()
[GblId]
main = $fMonadIO_$c>> @() @() sat_sHq sat_sHr
Why is that? I would have expected that the call chain main >-> $fMonadIO_$c>> >-> $dm>> would have resulted in a specialization along the lines of:
$dm>>_IO :: forall a b. IO a -> IO b -> IO b
=_IO :: forall a b. IO a -> (a -> IO b) -> IO b
With appropriate definitions that can then be simplified away.
But none of this seems to happen -- $dm>> doesn't get an IO-specific version, and so $fMonadIO_$c>> still ends up with a dictionary-passing call to $dm>>. Isn't this exactly the situation that the specialiser is supposed to eliminate?
Thanks,
Gergo
From: Simon Peyton Jones