Subversion

ptable

[/] [PTypeInference.hs] - Rev 6

Compare with Previous - Blame


{-# OPTIONS -fglasgow-exts #-}
module PTypeInference where

import Control.Monad.State
import qualified Data.Map as Map

import qualified Data.Transform.Type as TLT
import Data.Transform.RulesPF (simplifypf)
import Dynamics

import Language.Pointfree.Syntax as PF
import Language.Pointfree.Pretty

import PType
import AnnotatedPF as APF
import Matchings

import Debug.Trace

data Constraint = UnifiesT PType PType | UnifiesF PFctr PFctr | UnifiesIso PType PType -- UnifiesIso breaks only when the first unifies with some Mu F, situation where the second has to unify with F (Mu F)
	deriving Show

instance Substitution PTypeSubst Constraint Constraint where
        subst s (UnifiesT t1 t2) = UnifiesT (subst s t1) (subst s t2)
        subst s (UnifiesF t1 t2) = UnifiesF (subst s t1) (subst s t2)
        subst s (UnifiesIso t1 t2) = UnifiesIso (subst s t1) (subst s t2)

-- | Unification of two lists of constraints.
-- first to be processed are types and functors constraints, last are the isomorphisms,
-- which can generate new types and functors constraints. process only stops when both have been processed.
unify :: MonadPlus m => ([Constraint],[Constraint]) -> StateT PTypeSubst m PTypeSubst
unify ([],[]) = get
unify (((UnifiesT (PList a) (PList b)):t),isocs) 		= unify $ ([UnifiesT a b] ++ t,isocs)
unify (((UnifiesT (PSet a) (PSet b)):t),isocs) 			= unify $ ([UnifiesT a b] ++ t,isocs) 
unify (((UnifiesT (PMap a b) (PMap c d)):t),isocs) 		= unify $ ([UnifiesT a c, UnifiesT b d] ++ t,isocs)
unify (((UnifiesT (PEither a b) (PEither c d)):t),isocs) 	= unify $ ([UnifiesT a c, UnifiesT b d] ++ t,isocs)
unify (((UnifiesT (PProd a b) (PProd c d)):t),isocs) 		= unify $ ([UnifiesT a c, UnifiesT b d] ++ t,isocs)
unify (((UnifiesT (PFunc a b) (PFunc c d)):t),isocs) 		= unify $ ([UnifiesT a c, UnifiesT b d] ++ t,isocs)
unify (((UnifiesT (PTag n1 a) (PTag n2 b)):t),isocs) | n1 == n2	= unify $ ([UnifiesT a b] ++ t,isocs) 
unify (((UnifiesT (PMu f) (PMu g)):t),isocs) 			= unify $ ([UnifiesF f g] ++ t,isocs)
unify (((UnifiesT (PPF a) (PPF b)):t),isocs) 			= unify $ ([UnifiesT a b] ++ t,isocs) 
unify (((UnifiesF PId PId):t),isocs) 				= unify $ (t,isocs)
unify (((UnifiesF (PK a) (PK b)):t),isocs) 			= unify $ ([UnifiesT a b] ++ t,isocs)
unify (((UnifiesF (f1 ::+:: g1) (f2 ::+:: g2)):t),isocs) 	= unify $ ([UnifiesF f1 f2, UnifiesF f1 f2] ++ t,isocs)
unify (((UnifiesF (f1 ::*:: g1) (f2 ::*:: g2)):t),isocs) 	= unify $ ([UnifiesF f1 f2, UnifiesF f1 f2] ++ t,isocs)
unify (((UnifiesT (PVar v1) (PVar v2)):t),isocs) | v1 == v2 	= unify $ (t,isocs)
unify (((UnifiesT (PVar v1) d2):t),isocs) 			= replace v1 d2 (t,isocs) >>= unify
unify (((UnifiesT d1 (PVar v2)):t),isocs) 			= replace v2 d1 (t,isocs) >>= unify
unify (((UnifiesT t1 t2):t),isocs) | t1 == t2 			= unify $ (t,isocs)
unify ([],((UnifiesIso (PMu f) t2):t))				= unify $ ([UnifiesT t2 (mapft f (PMu f))], t)
unify ([],((UnifiesIso (PVar v1) (PVar v2)):t)) | v1 == v2 	= unify $ ([],t)
unify ([],((UnifiesIso (PVar v1) d2):t)) 			= replace v1 d2 ([],t) >>= unify
unify ([],((UnifiesIso d1 (PVar v2)):t)) 			= replace v2 d1 ([],t) >>= unify
unify ([],h:t)  = error $ "Cannot unify "++show h
unify (h:t,isocs) = error $ "Cannot unify "++show h

replace :: MonadPlus m => String -> PType -> ([Constraint],[Constraint]) -> StateT PTypeSubst m ([Constraint],[Constraint])
replace v dt (cs,isocs) =
     do let s = Map.singleton v dt
        modify (subst s)
        modify (Map.insert v dt)
        return $ (map (subst s) cs, map (subst s) isocs)

-- | Gathers the constraints for type inference of a term according to a type, generating also
-- an annotated PF term
constraints :: MonadPlus m => PF.Term -> PType -> StateT ([String], Map.Map String PType) m (([Constraint],[Constraint]), APF.Term PType)
constraints ID (PFunc a b) = return (([UnifiesT a b],[]), TID a)
constraints (t1 :.: t2) (PFunc a b) =
     do nv <- fresh
        ((r2,r2iso),dt2) <- constraints t2 (PFunc a nv)
        ((r1,r1iso),dt1) <- constraints t1 (PFunc nv b)
        return $ ((r1 ++ r2, r1iso ++ r2iso), TComp dt1 dt2 nv)
constraints FST (PFunc a b) =
     do nv1 <- fresh
        nv2 <- fresh
        return (([UnifiesT a (nv1 `PProd` nv2), UnifiesT nv1 b],[]), TFST (nv1 `PProd` nv2))
constraints SND (PFunc a b) =
     do nv1 <- fresh
        nv2 <- fresh
        return (([UnifiesT a (nv1 `PProd` nv2), UnifiesT nv2 b],[]), TSND (nv1 `PProd` nv2))
constraints (t1 PF.:/\: t2) (PFunc a b) =
     do nv1 <- fresh
             nv2 <- fresh
             ((r1,r1iso),tt1) <- constraints t1 (PFunc a nv1)
             ((r2,r2iso),tt2) <- constraints t2 (PFunc a nv2)
        return ((([UnifiesT b (nv1 `PProd` nv2)] ++ (r1 ++ r2)), r1iso ++ r2iso), tt1 APF.:/\: tt2)
constraints INL (PFunc a b) =
     do nv1 <- fresh
        nv2 <- fresh
        return (([UnifiesT b (nv1 `PEither` nv2), UnifiesT nv1 a],[]), TINL (nv1 `PEither` nv2))
constraints INR (PFunc a b) =
     do nv1 <- fresh
        nv2 <- fresh
        return (([UnifiesT b (nv1 `PEither` nv2), UnifiesT nv2 a],[]), TINR (nv1 `PEither` nv2))
constraints (t1 PF.:\/: t2) (PFunc a b) =
     do nv1 <- fresh
             nv2 <- fresh
             ((r1,r1iso),tt1) <- constraints t1 (nv1 `PFunc` b)
             ((r2,r2iso),tt2) <- constraints t2 (nv2 `PFunc` b)
        return ((([UnifiesT a (nv1 `PEither` nv2)] ++ (r1 ++ r2)), r1iso ++ r2iso), tt1 APF.:\/: tt2)
constraints AP (PFunc a b) =
     do nv1 <- fresh
             nv2 <- fresh
             nv3 <- fresh
             nv4 <- fresh
        return (([UnifiesT a (nv1 `PProd` nv2), UnifiesT nv1 (nv3 `PFunc` nv4)
                ,UnifiesT nv3 nv2, UnifiesT nv4 b],[]), TAP (PFunc nv3 nv4))
constraints (Curry t1) (PFunc a b) =
     do nv1 <- fresh
             nv2 <- fresh
        ((r1,r1iso),tt1) <- constraints t1 ((a `PProd` nv1) `PFunc` nv2)
        return ((([UnifiesT b (nv1 `PFunc` nv2)] ++ r1), r1iso), TCurry tt1)
constraints BANG (PFunc a b) = return (([UnifiesT b POne],[]), TBANG a)
constraints (Point str) (PFunc a b) = return (([UnifiesT a POne],[]), TPoint str b)
constraints IN  (PFunc a b) = return (([],[UnifiesIso b a]), TIN b)
--     do PVar nv1 <- fresh
--     	return ([UnifiesT a (PVar ('f':nv1)),UnifiesT b (PVar ('m':nv1))], TIN b)
constraints OUT (PFunc a b) = return (([],[UnifiesIso a b]), TOUT a)
--     do PVar nv1 <- fresh
--     	return ([UnifiesT a (PVar ('m':nv1)),UnifiesT b (PVar ('f':nv1))], TOUT a)
--constraints (Hylo (Mu f) t1 t2) (a `PFunc` b) =
--     do (r1,tt1) <- constraints t1 ((mapft f b) `PFunc` b)
--	(r2,tt2) <- constraints t2 (a `PFunc` (mapft f a))
--	return ((r1 ++ r2), THylo (Mu f) tt1 tt2)
constraints (Macro "(-|-)" [t1,t2]) (PFunc a b) =
     do nv1 <- fresh
             nv2 <- fresh
             nv3 <- fresh
             nv4 <- fresh
        ((r1,r1iso),tt1) <- constraints t1 (nv1 `PFunc` nv3)
        ((r2,r2iso),tt2) <- constraints t2 (nv2 `PFunc` nv4)
        return (([UnifiesT a (nv1 `PEither` nv2), UnifiesT b (nv3 `PEither` nv4)]
                ++ (r1 ++ r2), r1iso ++ r2iso), tt1 :-|-: tt2)
constraints (Macro "(><)" [t1,t2]) (PFunc a b) =
     do nv1 <- fresh
             nv2 <- fresh
             nv3 <- fresh
             nv4 <- fresh
        ((r1,r1iso),tt1) <- constraints t1 (nv1 `PFunc` nv3)
        ((r2,r2iso),tt2) <- constraints t2 (nv2 `PFunc` nv4)
        return (([UnifiesT a (nv1 `PProd` nv2), UnifiesT b (nv3 `PProd` nv4)]
                ++ (r1 ++ r2), r1iso ++ r2iso), tt1 :><: tt2)
constraints (Macro str []) (PFunc a b) =
     do funcs <- gets snd
        maybe (return (([],[]), TMacro str (PFunc a b) []))
              (\(PFunc a' b') -> return (([UnifiesT a a',UnifiesT b b'],[]), TMacro str (PFunc a b) []))
              (Map.lookup str funcs)
--constraints (Macro str lpf) (PFunc a b) =
constraints _ _ = mzero

-- | Infers a typed PF from an expected polymorphic type and an untyped term. It also receives 
-- an environment of defined functions and their types.
inferPoly :: (Map.Map String PType, [(PFctr, String)]) -> PType -> PF.Term -> Maybe DynPF
inferPoly (funcs,pfcnames) gtype term =
     do trace ("Inferring "++show term++"\nwith type "++show gtype++"\n") $ do
        (cts,tterm) <- evalStateT (constraints term gtype) (freshvars, funcs)
            s <- evalStateT (unify cts) Map.empty
        DynType t@(a `TLT.Func` b) <- ptype2type gtype
        let tterm' = subst s tterm
        pf <- tpf2pf pfcnames t tterm'
        return $ DynPF t pf

-- | Infers a typed PF from an expected type and an untyped term. It also receives 
-- an environment of defined functions and their types.
infer :: (Map.Map String PType, [(PFctr,String)]) -> TLT.Type (a -> b) -> PF.Term -> Maybe (TLT.PF (a -> b))
infer (funcs,pfcnames) t@(a `TLT.Func` b) term =
     do let gtype = type2ptype t
             (cts,tterm) <- evalStateT (constraints term gtype) (freshvars, funcs)
            s <- evalStateT (unify cts) Map.empty
        let tterm' = subst s tterm
--	trace (show tterm') $ do
--	trace (show pfcnames) $ do
--	trace (show t) $ do
	tpf2pf pfcnames t tterm'

-- auxiliars
fresh :: MonadPlus m => StateT ([String],t) m PType
fresh =
     do name <- gets (head . fst)
             modify (\(v,t) -> (tail v,t))
        return (PVar name)

freshvars = ["x"++n | n <- map show [1..]]

-- examples
ex1 = mapft (PK POne ::+:: (PK PInt ::*:: PId)) PInt

ex9 = infer
        (Map.empty,[])
        (((TLT.Int `TLT.Prod` TLT.Char) `TLT.Prod` TLT.One) `TLT.Func` (TLT.Char))
        (SND :.: FST)

ex2 = infer
        (Map.empty,[(PK POne ::+:: PId,"Nat")])
	(TLT.Func (TLT.One `TLT.Either` (TLT.Mu (TLT.K TLT.One TLT.:+: TLT.Id))) (TLT.Mu (TLT.K TLT.One TLT.:+: TLT.Id)))
        (PF.FST PF.:.: (PF.ID PF.:/\: PF.BANG) PF.:.: PF.IN PF.:.: PF.SND :.: (PF.BANG PF.:/\: PF.ID))

ex3 = infer
        ((Map.insert "swap" (PFunc ((PVar "a") `PProd` (PVar "b")) ((PVar "b") `PProd` (PVar "a"))) Map.empty),[])
        (((TLT.Int `TLT.Prod` TLT.Char) `TLT.Prod` TLT.One) `TLT.Func` (TLT.One `TLT.Prod` TLT.Char))
        ((BANG PF.:/\: (SND :.: SND)) :.: (Macro "swap" []))

--ex4 :: Maybe (TLT.PF a)
ex4 = ex3 >>= return . simplifypf TLT.typeof

ex5 = infer
        ((Map.insert "eithr" (((PVar "a" `PFunc` PVar "c") `PProd` (PVar "b" `PFunc` PVar "c")) `PFunc` ((PEither (PVar "a") (PVar "b")) `PFunc` PVar "c")) Map.empty),[(PK POne ::+:: PId,"Nat")])
	t5 pf5

t5 =  ((TLT.Either TLT.One (TLT.Mu ((TLT.K TLT.One)TLT.:+:TLT.Id))) `TLT.Func` (TLT.Mu ((TLT.K TLT.One) TLT.:+: TLT.Id)))
pf5 = PF.AP PF.:.: pf6
pf6 = pf7 PF.:/\: PF.ID 
pf7 = PF.Curry pf8 PF.:.: PF.BANG
pf8 = PF.AP PF.:.: pf9
pf9 = pf10 PF.:/\: PF.SND
pf10 = (PF.Macro "eithr" []) PF.:.: pf11
pf11 = PF.Curry pf12 PF.:/\: PF.Curry pf13
pf12 = PF.IN PF.:.: PF.INL PF.:.: PF.BANG
pf13 = PF.IN PF.:.: PF.INR PF.:.: PF.SND

t6 = TLT.Id TLT.:+: (TLT.K TLT.Int TLT.:+: (TLT.K TLT.Int TLT.:*: (((TLT.Id TLT.:+: TLT.K TLT.One) TLT.:*: TLT.Id) TLT.:+: TLT.K TLT.Char)))


Theme by Vikram Singh | Powered by WebSVN v1.61