Skip to content

Making Dictionaries

Andrew Farmer edited this page Nov 14, 2013 · 7 revisions

Based on what is done in typecheck/TcInstDcls.lhs, I think the following will possibly allow us to piece together a Typeable dictionary from a Type. Most of this is based on this bit starting on line 563 of that file:

        -- Finally, construct the Core representation of the instance.
        -- (This no longer includes the associated types.)
        ; dfun_name <- newDFunName clas inst_tys (getLoc poly_ty)
                -- Dfun location is that of instance *header*

        ; overlap_flag <- getOverlapFlag
        ; (subst, tyvars') <- tcInstSkolTyVars tyvars
        ; let dfun      = mkDictFunId dfun_name tyvars theta clas inst_tys
              ispec     = mkLocalInstance dfun overlap_flag tyvars' clas (substTys subst inst_tys)
                            -- Be sure to freshen those type variables, 
                            -- so they are sure not to appear in any lookup
              inst_info = InstInfo { iSpec  = ispec, iBinds = VanillaInst binds uprags False }

        ; return ( [inst_info], tyfam_insts0 ++ concat tyfam_insts1 ++ datafam_insts) }

Assuming we can make a Name for the class, we can look up the Class with:

-- typecheck/TcEnv.lhs
tcLookupClass :: Name -> TcM Class

In the case of Typeable, which is what Conal wants, we can use Typeable's built-in Name:

-- prelude/PrelNames.lhs
typeableClassName :: Name

Then we can make a name for the DFun, supplying the appropriate type arguments. In the case of Typeable, wouldn't this always be a singleton list? That seems to be what TcGenGenerics.lhs does for Data. The SrcSpan can be noSrcSpan.

-- Make a name for the dict fun for an instance decl.
-- It's an *external* name, like other top-level names.
-- typecheck/TcEnv.lhs
newDFunName :: Class -> [Type] -> SrcSpan -> TcM Name

I think once we have this name, we can look up the appropriate Id. If the lookup fails, then we need to construct the Id ourselves, using the Name as the first argument to:

-- basicTypes/MkId.lhs
mkDictFunId :: Name      -- Name to use for the dict fun;
            -> [TyVar]
            -> ThetaType
            -> Class 
            -> [Type]
            -> Id

Following a few functions, the [TyVar] become the forall-quantified type variables in the type of the Id, I believe. Not clear what the ThetaType is... superclass constraint?

Then we can make use of mkLocalInstance:

mkLocalInstance :: DFunId -> OverlapFlag
                -> [TyVar] -> Class -> [Type]
                -> ClsInst

And make a call to this big function which seems to set up the UnfoldingInfo and all that:

-- typecheck/TcInstDcls.lhs
tcInstDecl2 :: InstInfo Name -> TcM (LHsBinds Id)

Finally we use the desugarer to generate CoreExpr:

dsLHsBinds :: LHsBinds Id -> DsM [(Id,CoreExpr)]

Putting it together-ish (question marks on variables that I don't know how to get):

-- tys = [targetTy] (I think?)
tysToInstBinds :: [Type] -> TcM (LHsBinds Id)
tysToInstBinds tys = do
  overlap_flag <- getOverlapFlag
  cls <- tcLookupClass typeableClassName
  dfun_name <- newDFunName cls tys noSrcSpan
  -- do a lookup of dfun_name in a name cache?? not sure
  (subst, tyvars') <- tcInstSkolTyVars tyvars?
  let dfun_id = mkDictFunId dfun_name tyvars? thetaTy? cls tys
      ispec = mkLocalInstance dfun_id overlap_flag tyvars' cls (substTys subst tys)
  tcInstDecl2 (InstInfo { iSpec  = ispec, iBinds = VanillaInst binds? uprags? False }

-- runTcMToCoreM is Nick's hypothetical means of running TcM stuff
-- runDsMToCoreM doesn't exist... can we run the DsM monad inside CoreM?
typeToDictBinds :: Type -> CoreM [(Id,CoreExpr)]
typeToDictBinds ty = runTcMToCoreM (tysToInstBinds [ty]) >>= runDsMToCoreM . dsLHsBinds

What exactly have we gotten out? Maybe instead of calling tcInstDecl2 directly we can just pull out the parts that set up the DFunUnfolding and INLINE/SPECIALIZE flags and build a CoreExpr directly, bypassing the need to run dsLHsBinds.

Clone this wiki locally