packages feed

LambdaPrettyQuote-0.0.0.7: src/Language/Lambda/SimplyTyped/Arbitrary.hs

module Language.Lambda.SimplyTyped.Arbitrary (
    module Language.Lambda.Common.Arbitrary,
    Env,
    gen_type,
    gen_expr,
    --gen_env,
    gen_with_env,
    shrink_expr
) where
import Test.QuickCheck
import Control.Applicative ((<*>), (<$>))
import Data.List
import Language.Lambda.SimplyTyped.Syntax
import Control.Monad.RWS.Strict
import Control.Applicative
import Test.QuickCheck.Gen
import Data.Tuple.Select
import Language.Lambda.Common.Arbitrary
import Data.Maybe
import Debug.Trace.Helpers
import Debug.Trace

type Env a s = [(s, Type a)]

null_const_gen = arbitrary :: Gen (Maybe ())

gen_type :: (Eq a, Eq s) => Gen a -> Gen s -> Gen (Type a)
gen_type x y = gen_with_env arb_type x y $ const null_const_gen

gen_expr :: (Eq a, Eq s) => Gen a -> Gen s -> (Type a -> Gen (Maybe c)) -> Gen (Expr s a c)
gen_expr = gen_with_env arb_expr

shrink_expr :: Expr s a c -> [Expr s a c]
shrink_expr x@(Constant _) = []
shrink_expr x@(Var _)      = []
shrink_expr (App x y)      = []
shrink_expr (Lam s t e)    = []

gen_with_env :: (Eq a, Eq s) => EnvGen a s c b -> Gen a -> Gen s -> (Type a -> Gen (Maybe c)) -> Gen b
gen_with_env gen x y z = sized $ \i -> gen_with_env' gen (min i 5) x y z
    
gen_with_env' :: (Eq a, Eq s) => EnvGen a s c b -> Int -> Gen a -> Gen s -> (Type a -> Gen (Maybe c)) -> Gen b
gen_with_env' gen size a_gen s_gen c_gen = do
    (result, _) <- evalRWST gen (a_gen, s_gen, size, c_gen, []) ()
    return result

type EnvGen a s c = RWST (Gen a, Gen s, Int, Type a -> Gen (Maybe c), (Env a s)) () () Gen

arb_type :: (Eq a, Eq s) => EnvGen a s c (Type a)
arb_type = arb_type' =<< get_size 

arb_type' :: (Eq a, Eq s) => Int -> EnvGen a s c (Type a)
arb_type' 0    = Base <$> arb_base
arb_type' size = do
    option <- lift (choose (0, 1 :: Int))
    case option of
        0 -> Base  <$> arb_base
        1 -> Arrow <$> arb_type' (size - 1) <*> arb_type' (size - 1)

arb_expr :: (Eq a, Eq s) => EnvGen a s c (Expr s a c)
arb_expr = trace ("arb_expr") $ do
    i <- get_size 
    input  <- arb_type
    output <- arb_type
    arb_lam i (Arrow input output)

--This is good, but it is not useful for 
arb_var typ = do
    lookuped_value <- lookup_var_by_type typ
    case lookuped_value of
        (Just x) -> return $ Var $ fst x
        _ -> error "bad symbol name"
 
var_type_exists :: (Eq a, Eq s) => Type a -> EnvGen a s c (Bool)
var_type_exists typ = isJust <$> lookup_var_by_type typ
    
lookup_var_by_type :: (Eq a, Eq s) => Type a -> EnvGen a s c (Maybe (s, Type a))
lookup_var_by_type typ = do
    vars <- gets_env (filter ((typ==) . snd))
    if length vars > 0 
        then do v <- lift $ elements vars
                return $ Just v 
        else return Nothing
 
-- the right has to be it
-- and the left has to be type -> whatever it was told to be  
arb_app i typ = do
     output_type <- arb_type
     let f = Arrow output_type typ
     arb_app_typ i f output_type

arb_app_typ i input_type output_type = trace ("arb_app_typ" ++ show i) $ do
    App <$> arb_expr' input_type (i - 1) <*> arb_expr' output_type (i - 1)


fourth f (x, y, z, w, u) = (x, y, z, w, u)

arb_lam :: (Eq a, Eq s) => Int -> Type a -> EnvGen a s c (Expr s a c) 
arb_lam 0 x = terminal_lambda x
arb_lam i (Arrow input output) = do
    sym <- uniq_sym
    local (fourth (extend sym input)) $ do 
        Lam sym input <$> (arb_expr' output (i - 1))

arb_expr' :: (Eq a, Eq s) => Type a -> Int -> EnvGen a s c (Expr s a c)
arb_expr' typ i = trace ("arb_expr'" ++ show i) $ do
    option <-lift $ choose (0, 10 :: Int)
    if option == 0
        then attemp_constant_expr typ i  
        else non_constant_expr typ i
        
app_or_lam typ 0 = terminal_lambda typ 
app_or_lam typ@(Arrow _ _) i = trace ("app_or_lam" ++ show i) $ do
    option <- lift arbitrary
    if option
        then arb_app i typ
        else arb_lam i typ
app_or_lam typ i = trace ("app_or_lam" ++ show i) $ do
    arb_app i typ
        
terminal_lambda :: (Eq a, Eq s) => Type a -> EnvGen a s c (Expr s a c) 
terminal_lambda typ@(Base _) = do 
    c <- arb_constant typ
    return $ Constant $ fromJust c
terminal_lambda (Arrow input output) = do
    sym <- uniq_sym
    Lam sym input <$> terminal_lambda output

     
non_constant_expr :: (Eq a, Eq s) => Type a -> Int -> EnvGen a s c (Expr s a c)
non_constant_expr typ@(Arrow _ _) 0 = arb_lam 0 typ
non_constant_expr typ@(Arrow _ _) i = trace ("non_constant_expr" ++ show i) $ do
        option <- lift $ choose (0, 2 :: Int)
        case option of 
            0 -> do can_make_var <- var_type_exists typ
                    if can_make_var
                        then arb_var typ
                        else app_or_lam typ i
            1 -> arb_app i typ
            2 -> arb_lam i typ
non_constant_expr typ@(Base _) i = trace ("non_constant_expr" ++ show i) $ do
        c <- arb_constant typ
        return $ Constant $ fromJust c

attemp_constant_expr :: (Eq a, Eq s) => Type a -> Int -> EnvGen a s c (Expr s a c)
attemp_constant_expr typ i = trace ("attemp_constant_expr" ++ show i) $ do
    constant <- arb_constant typ
    case constant of
        Just x  -> return $ Constant x
        Nothing -> non_constant_expr typ i
            
extend :: (Eq a, Eq s) => s -> Type a -> Env a s -> Env a s
extend s t xs = (s, t):xs

get_env :: (Eq a, Eq s) => EnvGen a s c (Env a s)
get_env = asks sel5

gets_env :: (Eq a, Eq s) => (Env a s -> d) ->  EnvGen a s c d
gets_env f = asks (f . sel5)
    
arb_s :: (Eq a, Eq s) => EnvGen a s c s
arb_s = lift =<< asks sel2
    
arb_base :: (Eq a, Eq s) => EnvGen a s c a
arb_base = lift =<< asks sel1

get_size :: (Eq a, Eq s) => EnvGen a s c Int
get_size = asks ((\x -> trace ("size " ++ show x) x) . sel3)

arb_constant :: (Eq a, Eq s) => (Type a) -> EnvGen a s c (Maybe c)
arb_constant x = lift =<< asks (($ x) . sel4)

uniq_sym :: (Eq a, Eq s) => EnvGen a s c s
uniq_sym = do
    s_gen <- asks sel2
    env <- get_env
    lift $ suchThat s_gen ( `notElem` (map fst env))