packages feed

th-instances-0.1.0.14: src/Language/Haskell/TH/Instances.hs

{-# LANGUAGE TemplateHaskell, QuasiQuotes #-}
{- | A grab bag of useful instances for Template Haskell types -}
module Language.Haskell.TH.Instances (
    module Language.Haskell.TH.Lift,
    module Language.Haskell.TH.LiftInstances,
    haskell_98_data_dec,
    type_arb, 
    kind_arb,
    haskell_98_type_arb,
    primitive_types
) where
    
import Language.Haskell.TH
import Language.Haskell.TH.Lift
import Language.Haskell.TH.Syntax
import Data.String
import Test.QuickCheck
import Control.Applicative
import Test.QuickCheck.Instances.Char
import Control.Monad.Reader
import Data.List
import Language.Haskell.TH.LiftInstances
import Data.Char
import Data.DeriveTH

import qualified Language.Haskell.TH.Lift as L

clamp x y = if x < y
    then x
    else y

instance IsString Name where
    fromString x = mkName x
    
instance Arbitrary Name where
    arbitrary = sized $ \x -> do
         c <- lowerAlpha
         mkName <$> (c:) <$> vectorOf (clamp 20 x) (oneof [numeric, lowerAlpha, upperAlpha])
        
arb_constructor_name = do 
    x <- upperAlpha
    name_size <- choose (5, 20)
    xs <- sized (\x -> vectorOf name_size (oneof [numeric, lowerAlpha, upperAlpha]))
    return $ mkName $ x:xs

instance Arbitrary Type where
    arbitrary = sized type_arb
    shrink (VarT _) = []
    shrink (ConT _) = []
    shrink (TupleT _) = []
    shrink (UnboxedTupleT _) = []
    shrink (ArrowT) = []
    shrink (ListT) = []
    shrink (ForallT x y z) = [ForallT x' y' z' | x' <- shrink x, y' <- shrink y, 
                                                 z' <- shrink z]    
    shrink (SigT typ knd)  = [SigT t k | t <- shrink typ, k <- shrink knd]
    shrink (AppT x y)      = [x, y]
    
    
type_arb :: Int -> Gen Type       
type_arb depth = do
        let new_depth = depth `div` 2
            max_option = if depth > 0 then 8 else 5 :: Int
        typ <- choose (0, max_option)
        case typ of
            0 -> VarT <$> mkName <$> vectorOf 20 lowerAlpha
            1 -> ConT <$> arb_constructor_name
            2 -> TupleT <$> arbitrary
            3 -> UnboxedTupleT <$> arbitrary 
            4 -> return ArrowT
            5 -> return ListT
            6 -> ForallT <$> vectorOf (clamp 5 new_depth) (arb_ty_var_bndr (clamp 3 new_depth)) <*> 
                             vectorOf (clamp 5 new_depth) (arb_pred        (clamp 3 new_depth)) <*> 
                             type_arb new_depth
            7 -> SigT <$> type_arb new_depth <*> kind_arb new_depth
            8 -> AppT <$> type_arb new_depth <*> type_arb new_depth
            
    
instance Arbitrary Kind where
    arbitrary = sized kind_arb

kind_arb :: Int -> Gen Kind        
kind_arb 0 = return StarK
kind_arb depth = do
    typ <- choose(0, 1 :: Int)
    case typ of 
        0 -> return StarK
        1 -> ArrowK <$> kind_arb (depth `div` 2)
                    <*> kind_arb (depth `div` 2)
    
haskell_98_type_arb depth = do
    let max_option = if depth > 0 then 6 else (5 :: Int)
    typ <- choose (0, max_option)
    case typ of
        0 -> VarT <$> mkName <$> listOf lowerAlpha
        1 -> ConT <$> arb_constructor_name
        2 -> TupleT <$> arbitrary
        3 -> UnboxedTupleT <$> arbitrary 
        4 -> return ArrowT
        5 -> return ListT
        6 -> AppT <$> haskell_98_type_arb (depth `div` 2) 
                  <*> haskell_98_type_arb (depth `div` 2)
        
letter_strings =  map (\x -> mkName $ (x:[])) $ take 26 ['a'..]

instance Arbitrary Strict where
    arbitrary = oneof [return IsStrict, return NotStrict]

instance Arbitrary TyVarBndr where
    arbitrary = sized arb_ty_var_bndr where

arb_ty_var_bndr 0 = PlainTV <$> arbitrary
arb_ty_var_bndr size = do
    option <- arbitrary
    if option 
        then PlainTV  <$> arbitrary 
        else KindedTV <$> arbitrary <*> kind_arb (size `div` 2)
        

instance Arbitrary Pred where
    arbitrary = sized arb_pred where


arb_pred 0 = return $ ClassP (mkName "test") [ConT $ mkName "test"]
arb_pred size = do
    option <- arbitrary
    if option 
        then ClassP <$> arbitrary <*> vectorOf size (type_arb (size `div` 2))
        else EqualP <$> type_arb (size `div` 2) <*>  type_arb (size `div` 2)

instance Arbitrary Con where
    arbitrary = sized arb_con where

arb_con 0 = arb_con' 0 (2 :: Int)
arb_con size = arb_con' size 3
arb_con' size max_option = do
    option <- choose (0, max_option)
    case option of 
        0 -> NormalC <$> arbitrary <*> arbitrary
        1 -> RecC <$> arbitrary <*> arbitrary
        2 -> InfixC <$> arbitrary <*> arbitrary <*> arbitrary
        3 -> ForallC <$> arbitrary <*> arbitrary <*> arb_con (size - 1) 
--the right way to do this is probably to gen a simply typed environment 
--and sample functions from it, and convert
--what I really need to do, is first I generate 

--name of data -> name of ty_var -> kind
--type KindEnv = [(Name, [(Name, Kind)])]

--look_up_kind env = undefined
--extend name kind = undefined

safe_prefix name =  map (replace_symbol . toLower) name

replace_symbol '[' = 'z'
replace_symbol ']' = 'q'
replace_symbol x = x

collect_kinded_tyvars :: Dec -> [TyVarBndr]
collect_kinded_tyvars (DataD _ _ tyvars _ _ ) = tyvars
collect_kinded_tyvars (NewtypeD _ _ tyvars _ _ ) = tyvars
 
prefix_ty_var :: Name -> TyVarBndr -> TyVarBndr
prefix_ty_var name (KindedTV ty_name kind) = KindedTV (mkName $ (safe_prefix $ nameBase name) ++ ("_") ++ (show ty_name)) kind

prefix_ty_vars :: Dec -> Dec
prefix_ty_vars (DataD x name tyvars z w ) = DataD x name (map (prefix_ty_var name) tyvars) z w
prefix_ty_vars (NewtypeD x name tyvars z w ) = NewtypeD x name (map (prefix_ty_var name) tyvars) z w

ty_var_kind :: TyVarBndr -> Kind
ty_var_kind (KindedTV _ kind) = kind

ty_var_name :: TyVarBndr -> Name
ty_var_name (KindedTV name _ ) = name
ty_var_name (PlainTV name) = name

set_ty_var_name :: Name -> TyVarBndr -> TyVarBndr
set_ty_var_name n (KindedTV _ k) = KindedTV n k

group_by_kind :: [TyVarBndr] -> [[TyVarBndr]]
group_by_kind tyvars = groupBy (\x y -> ty_var_kind x == ty_var_kind y ) tyvars

possibly_share :: Bool -> [TyVarBndr] -> [TyVarBndr]
--possibly_share True (x:xs) = result where
--    name   = ty_var_name x
--    new_xs = map (set_ty_var_name name) xs
--   result = x:xs
possibly_share _ x = x

possibly_make_plain :: Bool -> TyVarBndr -> TyVarBndr
possibly_make_plain _ (KindedTV n _) = PlainTV n
--possibly_make_plain _ x = x

dec_to_typ :: Dec -> Type
dec_to_typ (DataD _ name ty_vars _ _) = foldl' AppT (ConT name) $ map (VarT . ty_var_name) ty_vars
dec_to_typ (NewtypeD _ name ty_vars _ _) = foldl' AppT (ConT name) $ map (VarT . ty_var_name) ty_vars

--type KindContext = ReaderT KindEnv Gen

haskell_98_data_dec :: [Dec] -> Gen Dec
haskell_98_data_dec other_types = do
    --all of the dec must be explictly kinded!
    name <- arb_constructor_name
    ty_var_size <- choose (0, 10)
    typ_vars    <- vectorOf ty_var_size (elements letter_strings)
                  
    concre_size <- choose (0, 10)
    concre_typs <- vectorOf concre_size (elements other_types)
    
    let renamed_concre_decs = map prefix_ty_vars concre_typs
        renamed_concre_typs = map dec_to_typ renamed_concre_decs
        all_ty_var_bndrs    = nub $ concatMap collect_kinded_tyvars renamed_concre_decs
        grouped = group_by_kind all_ty_var_bndrs
    
    should_share <- vectorOf (length grouped) arbitrary
        
    let shared  = concat $ zipWith possibly_share should_share grouped
    
    should_make_plain <- vectorOf (length shared) arbitrary

    let ty_var_bndrs  = zipWith possibly_make_plain should_make_plain shared
        typ_var_names = map ty_var_name ty_var_bndrs    
        var_types     = map VarT typ_var_names
    cons <- if length renamed_concre_typs > 0 
               then mapM arb_con_with_types =<< small_list_of (small_list_of $ elements (renamed_concre_typs))  -- ++ var_types
               else (:[]) <$> arb_con_with_types []
    index        <- choose(0, length cons - 1)
    
    return $ DataD [] name ty_var_bndrs cons [] 
    
arb_field_name = do
        x <- lowerAlpha
        name_size <- choose (10, 30)
        xs <- vectorOf name_size (oneof [numeric, lowerAlpha, upperAlpha])
        return $ mkName $ x:xs

arb_con_with_types :: [Type] -> Gen Con
arb_con_with_types xs = do
    name <- arb_constructor_name
    ss <- vectorOf (length xs) $ oneof [return IsStrict, return NotStrict]
    option <- choose (0, 1 :: Int)
    case option of
        0 -> return $ NormalC name $ zip ss xs
        1 -> do
             field_names <- vectorOf (length xs) arb_field_name
             let var_strict_types = zip3 field_names ss xs
             return $ RecC name var_strict_types
             


primitive_types = $(L.lift =<< mapM explictly_kind [''Int, ''Bool, ''Char, ''Float, ''[]])
    

small_list_of elems = do
    size <- choose (0, 10)
    vectorOf size elems