{-# LANGUAGE CPP #-} -- | Translating Agda types to Haskell types. Used to ensure that imported -- Haskell functions have the right type. module Agda.Compiler.HaskellTypes where import Control.Applicative import Control.Monad.Error import Data.Char import Agda.Syntax.Common import Agda.Syntax.Internal import Agda.TypeChecking.Monad import Agda.TypeChecking.Pretty import Agda.TypeChecking.Reduce import Agda.TypeChecking.Rules.Builtin.Coinduction import Agda.TypeChecking.Substitute import Agda.TypeChecking.Free import Agda.Utils.Monad import Agda.Utils.Impossible #include "../undefined.h" type HaskellKind = String hsStar :: HaskellKind hsStar = "*" hsKFun :: HaskellKind -> HaskellKind -> HaskellKind hsKFun k l = "(" ++ k ++ " -> " ++ l ++ ")" hsFun :: HaskellKind -> HaskellKind -> HaskellKind hsFun a b = "(" ++ a ++ " -> " ++ b ++ ")" hsUnit :: HaskellType hsUnit = "()" hsVar :: Name -> HaskellType hsVar x = "x" ++ concatMap encode (show x) where okChars = ['a'..'z'] ++ ['A'..'Y'] ++ "_'" encode 'Z' = "ZZ" encode c | c `elem` okChars = [c] | otherwise = "Z" ++ show (fromEnum c) hsApp :: String -> [HaskellType] -> HaskellType hsApp d [] = d hsApp d as = "(" ++ unwords (d : as) ++ ")" hsForall :: String -> HaskellType -> HaskellType hsForall x a = "(forall " ++ x ++ ". " ++ a ++ ")" notAHaskellKind :: Type -> TCM a notAHaskellKind a = do err <- fsep $ pwords "The type" ++ [prettyTCM a] ++ pwords "cannot be translated to a Haskell kind." typeError $ GenericError $ show err notAHaskellType :: Type -> TCM a notAHaskellType a = do err <- fsep $ pwords "The type" ++ [prettyTCM a] ++ pwords "cannot be translated to a Haskell type." typeError $ GenericError $ show err getHsType :: QName -> TCM HaskellType getHsType x = do d <- compiledHaskell . defCompiledRep <$> getConstInfo x case d of Just (HsType t) -> return t Just (HsDefn t c) -> return hsUnit _ -> notAHaskellType (El Prop $ Def x []) getHsVar :: Nat -> TCM HaskellCode getHsVar i = hsVar <$> nameOfBV i isHaskellKind :: Type -> TCM Bool isHaskellKind a = (const True <$> haskellKind a) `catchError` \_ -> return False haskellKind :: Type -> TCM HaskellKind haskellKind a = do a <- reduce a case unEl a of Sort _ -> return hsStar Pi a b -> hsKFun <$> haskellKind (unArg a) <*> underAbstraction a b haskellKind Def d _ -> do d <- compiledHaskell . defCompiledRep <$> getConstInfo d case d of Just (HsType t) -> return hsStar _ -> notAHaskellKind a _ -> notAHaskellKind a -- | Note that @Inf a b@, where @Inf@ is the INFINITY builtin, is -- translated to @@ (assuming that all coinductive -- builtins are defined). -- -- Note that if @haskellType@ supported universe polymorphism then the -- special treatment of INFINITY might not be needed. haskellType :: Type -> TCM HaskellType haskellType = liftTCM . fromType where fromArgs = mapM (fromTerm . unArg) fromType = fromTerm . unEl fromTerm v = do v <- reduce v reportSLn "compile.haskell.type" 50 $ "toHaskellType " ++ show v kit <- liftTCM coinductionKit let err = notAHaskellType (El Prop v) case v of Var x args -> hsApp <$> getHsVar x <*> fromArgs args Def d args | Just d == (nameOfInf <$> kit) -> case args of [a, b] -> fromTerm (unArg b) _ -> err Def d args -> hsApp <$> getHsType d <*> fromArgs args Pi a b -> if isBinderUsed b then underAbstraction a b $ \b -> hsForall <$> getHsVar 0 <*> (hsFun <$> fromType (unArg a) <*> fromType b) else hsFun <$> fromType (unArg a) <*> fromType (absApp b __IMPOSSIBLE__) Con c args -> hsApp <$> getHsType c <*> fromArgs args Lam{} -> err Level{} -> return hsUnit Lit{} -> return hsUnit Sort{} -> return hsUnit MetaV{} -> err DontCare{} -> err