src/HOL/Tools/Quickcheck/Narrowing_Engine.hs
author bulwahn
Tue Sep 06 16:40:22 2011 +0200 (2011-09-06)
changeset 44751 f523923d8182
parent 43079 4022892a2f28
child 45003 7591039fb6b4
permissions -rw-r--r--
avoid "Code" as structure name (cf. 3bc39cfe27fe)
     1 module Narrowing_Engine where {
     2 
     3 import Monad;
     4 import Control.Exception;
     5 import System.IO;
     6 import System.Exit;
     7 import Generated_Code;
     8 
     9 type Pos = [Int];
    10 
    11 -- Term refinement
    12 
    13 new :: Pos -> [[Narrowing_type]] -> [Narrowing_term];
    14 new p ps = [ Ctr c (zipWith (\i t -> Var (p++[i]) t) [0..] ts)
    15            | (c, ts) <- zip [0..] ps ];
    16 
    17 refine :: Narrowing_term -> Pos -> [Narrowing_term];
    18 refine (Var p (SumOfProd ss)) [] = new p ss;
    19 refine (Ctr c xs) p = map (Ctr c) (refineList xs p);
    20 
    21 refineList :: [Narrowing_term] -> Pos -> [[Narrowing_term]];
    22 refineList xs (i:is) = let (ls, x:rs) = splitAt i xs in [ls ++ y:rs | y <- refine x is];
    23 
    24 -- Find total instantiations of a partial value
    25 
    26 total :: Narrowing_term -> [Narrowing_term];
    27 total (Ctr c xs) = [Ctr c ys | ys <- mapM total xs];
    28 total (Var p (SumOfProd ss)) = [y | x <- new p ss, y <- total x];
    29 
    30 -- Answers
    31 
    32 answer :: a -> (a -> IO b) -> (Pos -> IO b) -> IO b;
    33 answer a known unknown =
    34   try (evaluate a) >>= (\res ->
    35      case res of
    36        Right b -> known b
    37        Left (ErrorCall ('\0':p)) -> unknown (map fromEnum p)
    38        Left e -> throw e);
    39 
    40 -- Refute
    41 
    42 str_of_list [] = "[]";
    43 str_of_list (x:xs) = "(" ++ x ++ " :: " ++ str_of_list xs ++ ")";
    44 
    45 report :: Result -> [Narrowing_term] -> IO Int;
    46 report r xs = putStrLn ("SOME (" ++ (str_of_list $ zipWith ($) (showArgs r) xs) ++ ")") >> hFlush stdout >> exitWith ExitSuccess;
    47 
    48 eval :: Bool -> (Bool -> IO a) -> (Pos -> IO a) -> IO a;
    49 eval p k u = answer p (\p -> answer p k u) u;
    50 
    51 ref :: Result -> [Narrowing_term] -> IO Int;
    52 ref r xs = eval (apply_fun r xs) (\res -> if res then return 1 else report r xs) (\p -> sumMapM (ref r) 1 (refineList xs p));
    53           
    54 refute :: Result -> IO Int;
    55 refute r = ref r (args r);
    56 
    57 sumMapM :: (a -> IO Int) -> Int -> [a] -> IO Int;
    58 sumMapM f n [] = return n;
    59 sumMapM f n (a:as) = seq n (do m <- f a ; sumMapM f (n+m) as);
    60 
    61 -- Testable
    62 
    63 instance Show Typerep where {
    64   show (Typerep c ts) = "Type (\"" ++ c ++ "\", " ++ show ts ++ ")";
    65 };
    66 
    67 instance Show Term where {
    68   show (Const c t) = "Const (\"" ++ c ++ "\", " ++ show t ++ ")";
    69   show (App s t) = "(" ++ show s ++ ") $ (" ++ show t ++ ")";
    70   show (Abs s ty t) = "Abs (\"" ++ s ++ "\", " ++ show ty ++ ", " ++ show t ++ ")";
    71   show (Free s ty) = "Free (\"" ++ s ++  "\", " ++ show ty ++ ")";
    72 };
    73 
    74 data Result =
    75   Result { args     :: [Narrowing_term]
    76          , showArgs :: [Narrowing_term -> String]
    77          , apply_fun    :: [Narrowing_term] -> Bool
    78          };
    79 
    80 data P = P (Int -> Int -> Result);
    81 
    82 run :: Testable a => ([Narrowing_term] -> a) -> Int -> Int -> Result;
    83 run a = let P f = property a in f;
    84 
    85 class Testable a where {
    86   property :: ([Narrowing_term] -> a) -> P;
    87 };
    88 
    89 instance Testable Bool where {
    90   property app = P $ \n d -> Result [] [] (app . reverse);
    91 };
    92 
    93 instance (Partial_term_of a, Narrowing a, Testable b) => Testable (a -> b) where {
    94   property f = P $ \n d ->
    95     let C t c = narrowing d
    96         c' = conv c
    97         r = run (\(x:xs) -> f xs (c' x)) (n+1) d
    98     in  r { args = Var [n] t : args r, showArgs = (show . partial_term_of (Type :: Itself a)) : showArgs r };
    99 };
   100 
   101 -- Top-level interface
   102 
   103 depthCheck :: Testable a => Int -> a -> IO ();
   104 depthCheck d p =
   105   (refute $ run (const p) 0 d) >> putStrLn ("NONE") >> hFlush stdout;
   106 
   107 smallCheck :: Testable a => Int -> a -> IO ();
   108 smallCheck d p = mapM_ (`depthCheck` p) [0..d] >> putStrLn ("NONE") >> hFlush stdout;
   109 
   110 }
   111