lambdabot-4.1: scripts/FT/FreeTheorems/Preparation.hs
-- Copyright 2006, Sascha Boehme.
-- | This module contains functions to process types before a theorem can be
-- generated out of them.
module FreeTheorems.Preparation (
prepare,
-- testing interface
-- testPreparation
) where
import FreeTheorems.Declarations (TypeDeclaration(..), getTypeDecl)
import FreeTheorems.Types
import Data.List (nub, delete)
-- import FreeTheorems.Test.ArbitraryTypes
-- import Test.QuickCheck (quickCheck)
-- | Prepares a type before a theorem can be generated out of it.
prepare :: Type -> Type
prepare = replaceTypeSynonyms . closure
-- | Computes the closure for a named type term. The returned type term contains
-- no free type variables anymore.
closure :: Type -> Type
closure t = foldr (\v t -> TypeForall v t) t (freeVariables t)
-- | Computes the free type variables for a type term.
-- This is a helper function for 'closure'.
freeVariables :: Type -> [TypeVariable]
freeVariables t =
case t of
TypeBasic _ -> []
TypeVar v -> [v]
TypeTermVar _ -> []
TypeCon _ ts -> nub $ concat $ map freeVariables ts
TypeList t1 -> freeVariables t1
TypeUnit -> []
TypeTuple ts -> nub $ concat $ map freeVariables ts
TypeFun t1 t2 -> nub $ concat $ map freeVariables [t1, t2]
TypeForall v t1 -> delete v (freeVariables t1)
-- | Replaces all type synonyms by its declaration's right-hand side.
-- Only type synonyms occurring in the set of user-defined types are replaced.
-- However, there may be no other type synonyms in the type term, anyway.
replaceTypeSynonyms :: Type -> Type
replaceTypeSynonyms t =
let replaceTS = replaceTypeSynonyms
in case t of
TypeBasic _ -> t
TypeVar _ -> t
TypeTermVar _ -> t
TypeCon c ts -> replaceByDecl c ts
TypeList t1 -> TypeList (replaceTS t1)
TypeUnit -> t
TypeTuple ts -> TypeTuple (map replaceTS ts)
TypeFun t1 t2 -> TypeFun (replaceTS t1) (replaceTS t2)
TypeForall v t1 -> TypeForall v (replaceTS t1)
-- | Replaces a type constructor by its declaration's right-hand side, if the
-- type constructor belongs to a type synonym. Otherwise calls
-- 'replaceTypeSynonyms' on the subtypes.
replaceByDecl :: TypeConstructor -> [Type] -> Type
replaceByDecl con ts =
case getTypeDecl con of
Nothing -> TypeCon con (map replaceTypeSynonyms ts)
Just decl -> let TypeDecl _ _ rhs = decl
in replaceTypeSynonyms (rhs ts)
--------------------------------------------------------------------------------
-- A list of tests for this module.
{-
testPreparation = do
putStr "closure of types works ... "
quickCheck prop_closure
putStr "type synonyms are replaced correctly ... "
quickCheck prop_replaceTypeSynonyms
putStr "preparation of types works ... "
quickCheck prop_prepare
-}
-- A closed type term does not contain any free variable.
prop_closure t =
(freeVariables (closure t) == [])
&& (closure t == closure (closure t))
-- Check that there are no type synonyms anymore and that further applications
-- of 'replaceTypeSynonyms' don't change the type anymore.
prop_replaceTypeSynonyms t =
(hasNoTypeSynonyms $ replaceTypeSynonyms t)
&& (replaceTypeSynonyms t == replaceTypeSynonyms (replaceTypeSynonyms t))
hasNoTypeSynonyms t =
case t of
TypeBasic _ -> True
TypeVar _ -> True
TypeCon c ts -> case getTypeDecl c of
Nothing -> and (map hasNoTypeSynonyms ts)
Just _ -> False
TypeList t1 -> hasNoTypeSynonyms t1
TypeUnit -> True
TypeTuple ts -> and (map hasNoTypeSynonyms ts)
TypeFun t1 t2 -> hasNoTypeSynonyms t1 && hasNoTypeSynonyms t2
TypeForall v t1 -> hasNoTypeSynonyms t1
otherwise -> False
-- Check that prepare does everything it is supposed to do, in any way.
prop_prepare t =
(prepare t == (replaceTypeSynonyms $ closure t))
&& (prepare t == (closure $ replaceTypeSynonyms t))