Hi Andreas,

unfortunately, a selector-based solution didn't either yield a
terminating example.

If you like you can inspect the attached code, maybe I did get something
wrong.

I will resonsider this in approx. one week; maybe we have to raise the
question seriously how maintenance of quickcheck/narrowing can go on.

Cheers,
        Florian

Am 14.01.2017 um 10:03 schrieb Andreas Lochbihler:
> Hi Florian,
> 
> Lukas may be able to answer this question better, but here's a comment:
> You do not need the lazy treatment of irrefutable patterns in Haskell as
> a primitive, because it is easy to emulate using selectors. That is, if
> we have a single-constructor HOL datatype
> 
> dataype 'a T = C (s1: 'a) (s2: 'a T) (s3: 'a T list)
> 
> then we can introduce a copy of the case operator by
> 
> definition case_lazy_T where "case_lazy_T = case_T"
> lemma [code]: "case_lazy_T f x = f (s1 x) (s2 x) (s3 x)"
> 
> Now, when you want to use the semantics of irrefutable patterns in
> let-bindings, use case_lazy_T in the code equation. If you really want
> to force the evaluation, then use case_T and compile it with the new
> scheme.
> 
> I have not tried this, but my guess is that if you do it this way for
> the three types narrowing_type narrowing_term narrowing_cons of
> Quickcheck_Narrowing and adjust the code equations for the constants in
> Quickcheck_Narrowing accordingly, then you get back the old behaviour.
> 
> Hope this helps,
> Andreas
> 
> On 14/01/17 09:33, Florian Haftmann wrote:
>> Hi Lukas,
>>
>> I am currently stuck with a problem in Quickcheck/Narrowing.
>>
>> After about 10 years it came to surface that code generation for Haskell
>> may produce irrefutable patterns due to pattern bindings in let clauses.
>> See <https://wiki.haskell.org/Lazy_pattern_match>; if I understand
>> <https://www.haskell.org/tutorial/patterns.html> correctly that
>> particular semantics allows fancy definitions like the following
>> fibonacci one-liner: »fib @ (1 : more_fib) = 1 : 1 : [ a + b | (a, b) <-
>> zip fib more_fib ]«.
>>
>> However the partial correctness approach of the code generator assumes
>> that pattern match clauses may silently be dropped, which is made use of
>> to translate the HOL-ish »partial« undefined conveniently. This breaks
>> down in presence of irrefutable patterns (see the post on isabelle-users
>> by Rene Thiemann).
>>
>> The correction is obvious: for Haskell, only local variables may be
>> bound by let clauses, but never patterns – these are solely bound by
>> case clauses, which are strict in Haskell (as in function equations).
>>
>> This however breaks Quickcheck/Narrowing where the lazy nature of
>> pattern bindings has been exploited, may be unconsciously. A minimal
>> example is attached (Quickcheck_Narrowing_Examples.thy) but I also
>> distilled the generated Haskell code:
>>
>> The same before and after:
>>     Typerep.hs
>>
>> Then the difference occurs:
>>     Generated_Code.hs
>>     Before: Generated_Code.A.hs
>>     After: Generated_Code.B.hs
>>
>> The same before and after:
>>     Narrowing_Engine.hs
>>     Main.hs
>>
>> The diff ist straight-forward to read:
>>
>>>     93,102c93,106
>>>     <   let {
>>>     <     (Narrowing_cons (Narrowing_sum_of_products ps) cfs) = f d;
>>>     <     (Narrowing_cons ta cas) = a (d - (1 :: Prelude.Int));
>>>     <     shallow = (0 :: Prelude.Int) < d && non_empty ta;
>>>     <     aa = (if shallow then map (\ cf (x : xs) -> cf xs (conv cas
>>> x)) cfs
>>>     <            else []);
>>>     <   } in Narrowing_cons
>>>     <          (Narrowing_sum_of_products
>>>     <            (if shallow then map (\ ab -> ta : ab) ps else []))
>>>     <          aa;
>>>     ---
>>>     >   (case f d of {
>>>     >     Narrowing_cons (Narrowing_sum_of_products ps) cfs ->
>>>     >       (case a (d - (1 :: Prelude.Int)) of {
>>>     >         Narrowing_cons ta cas ->
>>>     >           let {
>>>     >             shallow = (0 :: Prelude.Int) < d && non_empty ta;
>>>     >             aa = (if shallow then map (\ cf (x : xs) -> cf xs
>>> (conv cas x)) cfs
>>>     >                    else []);
>>>     >           } in Narrowing_cons
>>>     >                  (Narrowing_sum_of_products
>>>     >                    (if shallow then map (\ ab -> ta : ab) ps
>>> else []))
>>>     >                  aa;
>>>     >       });
>>>     >   });
>>>     112,115c116,122
>>>     <   let {
>>>     <     (Narrowing_cons (Narrowing_sum_of_products ssa) ca) = a d;
>>>     <     (Narrowing_cons (Narrowing_sum_of_products ssb) cb) = b d;
>>>     <   } in Narrowing_cons (Narrowing_sum_of_products (ssa ++ ssb))
>>> (ca ++ cb);
>>>     ---
>>>     >   (case a d of {
>>>     >     Narrowing_cons (Narrowing_sum_of_products ssa) ca ->
>>>     >       (case b d of {
>>>     >         Narrowing_cons (Narrowing_sum_of_products ssb) cb ->
>>>     >           Narrowing_cons (Narrowing_sum_of_products (ssa ++
>>> ssb)) (ca ++ cb);
>>>     >       });
>>>     >   });
>>
>> Unfortunately my knowledge is too restricted what could be done here to
>> restore the intended behaviour economically.
>>
>> Hence I ask whether you have an idea what is going wrong here.
>>
>> Thanks a lot!
>>
>>     Florian
>>
>>
>>
>> _______________________________________________
>> isabelle-dev mailing list
>> isabelle-...@in.tum.de
>> https://mailmanbroy.informatik.tu-muenchen.de/mailman/listinfo/isabelle-dev
>>
>>
> _______________________________________________
> isabelle-dev mailing list
> isabelle-...@in.tum.de
> https://mailmanbroy.informatik.tu-muenchen.de/mailman/listinfo/isabelle-dev

-- 

PGP available:
http://isabelle.in.tum.de/~haftmann/pgp/florian_haftmann_at_informatik_tu_muenchen_de
module
  Generated_Code(Narrowing_type(..), Narrowing_term(..), Term(..), Itself(..),
                  Typerepa(..), Partial_term_of(..), Is_testable(..),
                  Narrowing_cons(..), Narrowing(..), Term_of(..), Num(..),
                  Char(..), Nat(..), typerep_nat, term_of_nat, non_empty, conv,
                  apply, cons, sum, narrowing_nat, partial_term_of_nat,
                  typerep_bool, narrowing_bool, partial_term_of_bool,
                  narrowing_dummy_partial_term_of, narrowing_dummy_narrowing,
                  ensure_testable, equal_nat, value)
  where {

import Prelude ((==), (/=), (<), (<=), (>=), (>), (+), (-), (*), (/), (**),
  (>>=), (>>), (=<<), (&&), (||), (^), (^^), (.), ($), ($!), (++), (!!), Eq,
  error, id, return, not, fst, snd, map, filter, concat, concatMap, reverse,
  zip, null, takeWhile, dropWhile, all, any, Integer, negate, abs, divMod,
  String, Bool(True, False), Maybe(Nothing, Just));
import qualified Prelude;
import qualified Typerep;

newtype Narrowing_type = Narrowing_sum_of_products [[Narrowing_type]];

data Narrowing_term = Narrowing_variable [Prelude.Int] Narrowing_type
  | Narrowing_constructor Prelude.Int [Narrowing_term];

data Term = Const String Typerep.Typerep | App Term Term
  | Abs String Typerep.Typerep Term | Free String Typerep.Typerep;

data Itself a = Type;

class Typerepa a where {
  typerep :: Itself a -> Typerep.Typerep;
};

class (Typerepa a) => Partial_term_of a where {
  partial_term_of :: Itself a -> Narrowing_term -> Term;
};

class Is_testable a where {
};

data Narrowing_cons a = Narrowing_cons Narrowing_type [[Narrowing_term] -> a];

class Narrowing a where {
  narrowing :: Prelude.Int -> Narrowing_cons a;
};

class (Typerepa a) => Term_of a where {
  term_of :: a -> Term;
};

instance (Term_of a, Narrowing a, Partial_term_of a,
           Is_testable b) => Is_testable (a -> b) where {
};

data Num = One | Bit0 Num | Bit1 Num;

data Char = Zero_char | Char Num;

data Nat = Zero_nat | Suc Nat;

typerep_nat :: Itself Nat -> Typerep.Typerep;
typerep_nat t = Typerep.Typerep "Nat.nat" [];

instance Typerepa Nat where {
  typerep = typerep_nat;
};

term_of_nat :: Nat -> Term;
term_of_nat (Suc a) =
  App (Const "Nat.Suc"
        (Typerep.Typerep "fun"
          [Typerep.Typerep "Nat.nat" [], Typerep.Typerep "Nat.nat" []]))
    (term_of_nat a);
term_of_nat Zero_nat =
  Const "Nat.zero_nat_inst.zero_nat" (Typerep.Typerep "Nat.nat" []);

instance Term_of Nat where {
  term_of = term_of_nat;
};

non_empty :: Narrowing_type -> Bool;
non_empty (Narrowing_sum_of_products ps) = not (null ps);

conv :: forall a. [[Narrowing_term] -> a] -> Narrowing_term -> a;
conv cs (Narrowing_variable p uu) = error ('\0' : map Prelude.toEnum p);
conv cs (Narrowing_constructor i xs) = (cs !! i) xs;

apply ::
  forall a b.
    (Prelude.Int -> Narrowing_cons (a -> b)) ->
      (Prelude.Int -> Narrowing_cons a) -> Prelude.Int -> Narrowing_cons b;
apply f a d =
  let {
    (Narrowing_cons (Narrowing_sum_of_products ps) cfs) = f d;
    (Narrowing_cons ta cas) = a (d - (1 :: Prelude.Int));
    shallow = (0 :: Prelude.Int) < d && non_empty ta;
    aa = (if shallow then map (\ cf (x : xs) -> cf xs (conv cas x)) cfs
           else []);
  } in Narrowing_cons
         (Narrowing_sum_of_products
           (if shallow then map (\ ab -> ta : ab) ps else []))
         aa;

cons :: forall a. a -> Prelude.Int -> Narrowing_cons a;
cons a d = Narrowing_cons (Narrowing_sum_of_products [[]]) [(\ _ -> a)];

sum ::
  forall a.
    (Prelude.Int -> Narrowing_cons a) ->
      (Prelude.Int -> Narrowing_cons a) -> Prelude.Int -> Narrowing_cons a;
sum a b d =
  let {
    (Narrowing_cons (Narrowing_sum_of_products ssa) ca) = a d;
    (Narrowing_cons (Narrowing_sum_of_products ssb) cb) = b d;
  } in Narrowing_cons (Narrowing_sum_of_products (ssa ++ ssb)) (ca ++ cb);

narrowing_nat :: Prelude.Int -> Narrowing_cons Nat;
narrowing_nat = sum (cons Zero_nat) (apply (cons Suc) narrowing_nat);

instance Narrowing Nat where {
  narrowing = narrowing_nat;
};

partial_term_of_nat :: Itself Nat -> Narrowing_term -> Term;
partial_term_of_nat ty (Narrowing_constructor (1 :: Prelude.Int) [a]) =
  App (Const "Nat.Suc"
        (Typerep.Typerep "fun"
          [Typerep.Typerep "Nat.nat" [], Typerep.Typerep "Nat.nat" []]))
    (partial_term_of_nat Type a);
partial_term_of_nat ty (Narrowing_constructor (0 :: Prelude.Int) []) =
  Const "Nat.zero_nat_inst.zero_nat" (Typerep.Typerep "Nat.nat" []);
partial_term_of_nat ty (Narrowing_variable p tt) =
  Free "_" (Typerep.Typerep "Nat.nat" []);

instance Partial_term_of Nat where {
  partial_term_of = partial_term_of_nat;
};

typerep_bool :: Itself Bool -> Typerep.Typerep;
typerep_bool t = Typerep.Typerep "HOL.bool" [];

instance Typerepa Bool where {
  typerep = typerep_bool;
};

narrowing_bool :: Prelude.Int -> Narrowing_cons Bool;
narrowing_bool = sum (cons True) (cons False);

instance Narrowing Bool where {
  narrowing = narrowing_bool;
};

instance Is_testable Bool where {
};

partial_term_of_bool :: Itself Bool -> Narrowing_term -> Term;
partial_term_of_bool ty (Narrowing_constructor (1 :: Prelude.Int) []) =
  Const "HOL.False" (Typerep.Typerep "HOL.bool" []);
partial_term_of_bool ty (Narrowing_constructor (0 :: Prelude.Int) []) =
  Const "HOL.True" (Typerep.Typerep "HOL.bool" []);
partial_term_of_bool ty (Narrowing_variable p tt) =
  Free "_" (Typerep.Typerep "HOL.bool" []);

instance Partial_term_of Bool where {
  partial_term_of = partial_term_of_bool;
};

narrowing_dummy_partial_term_of ::
  forall a. (Partial_term_of a) => Itself a -> Narrowing_term -> Term;
narrowing_dummy_partial_term_of = partial_term_of;

narrowing_dummy_narrowing ::
  forall a. (Narrowing a) => Prelude.Int -> Narrowing_cons a;
narrowing_dummy_narrowing = narrowing;

ensure_testable :: forall a. (Is_testable a) => a -> a;
ensure_testable f =
  let {
    _ = (narrowing_dummy_narrowing :: Prelude.Int -> Narrowing_cons Bool);
    _ = (narrowing_dummy_partial_term_of ::
          Itself Bool -> Narrowing_term -> Term);
    _ = conv;
  } in f;

equal_nat :: Nat -> Nat -> Bool;
equal_nat Zero_nat (Suc x2) = False;
equal_nat (Suc x2) Zero_nat = False;
equal_nat (Suc x2) (Suc y2) = equal_nat x2 y2;
equal_nat Zero_nat Zero_nat = True;

value :: forall a. a -> Nat -> Nat -> Bool;
value dummy = ensure_testable (\ y x -> equal_nat x y);

}
module
  Generated_Code(Narrowing_type(..), Narrowing_term(..), Term(..), Itself(..),
                  Typerepa(..), Partial_term_of(..), Is_testable(..),
                  Narrowing_cons(..), Narrowing(..), Term_of(..), Num(..),
                  Char(..), Nat(..), typerep_nat, term_of_nat, apply_cons, conv,
                  apply, cons, sum, narrowing_nat, partial_term_of_nat,
                  typerep_bool, narrowing_bool, partial_term_of_bool,
                  narrowing_dummy_partial_term_of, narrowing_dummy_narrowing,
                  ensure_testable, equal_nat, value)
  where {

import Prelude ((==), (/=), (<), (<=), (>=), (>), (+), (-), (*), (/), (**),
  (>>=), (>>), (=<<), (&&), (||), (^), (^^), (.), ($), ($!), (++), (!!), Eq,
  error, id, return, not, fst, snd, map, filter, concat, concatMap, reverse,
  zip, null, takeWhile, dropWhile, all, any, Integer, negate, abs, divMod,
  String, Bool(True, False), Maybe(Nothing, Just));
import qualified Prelude;
import qualified Typerep;

newtype Narrowing_type = Narrowing_sum_of_products [[Narrowing_type]];

data Narrowing_term = Narrowing_variable [Prelude.Int] Narrowing_type
  | Narrowing_constructor Prelude.Int [Narrowing_term];

data Term = Const String Typerep.Typerep | App Term Term
  | Abs String Typerep.Typerep Term | Free String Typerep.Typerep;

data Itself a = Type;

class Typerepa a where {
  typerep :: Itself a -> Typerep.Typerep;
};

class (Typerepa a) => Partial_term_of a where {
  partial_term_of :: Itself a -> Narrowing_term -> Term;
};

class Is_testable a where {
};

data Narrowing_cons a = Narrowing_cons Narrowing_type [[Narrowing_term] -> a];

class Narrowing a where {
  narrowing :: Prelude.Int -> Narrowing_cons a;
};

class (Typerepa a) => Term_of a where {
  term_of :: a -> Term;
};

instance (Term_of a, Narrowing a, Partial_term_of a,
           Is_testable b) => Is_testable (a -> b) where {
};

data Num = One | Bit0 Num | Bit1 Num;

data Char = Zero_char | Char Num;

data Nat = Zero_nat | Suc Nat;

typerep_nat :: Itself Nat -> Typerep.Typerep;
typerep_nat t = Typerep.Typerep "Nat.nat" [];

instance Typerepa Nat where {
  typerep = typerep_nat;
};

term_of_nat :: Nat -> Term;
term_of_nat (Suc a) =
  App (Const "Nat.Suc"
        (Typerep.Typerep "fun"
          [Typerep.Typerep "Nat.nat" [], Typerep.Typerep "Nat.nat" []]))
    (term_of_nat a);
term_of_nat Zero_nat =
  Const "Nat.zero_nat_inst.zero_nat" (Typerep.Typerep "Nat.nat" []);

instance Term_of Nat where {
  term_of = term_of_nat;
};

apply_cons ::
  forall a b.
    ([[Narrowing_type]] -> [[Narrowing_term] -> a] -> b) ->
      Narrowing_cons a -> b;
apply_cons f (Narrowing_cons (Narrowing_sum_of_products tyss) cs) = f tyss cs;

conv :: forall a. [[Narrowing_term] -> a] -> Narrowing_term -> a;
conv cs (Narrowing_variable p uu) = error ('\0' : map Prelude.toEnum p);
conv cs (Narrowing_constructor i xs) = (cs !! i) xs;

apply ::
  forall a b.
    (Prelude.Int -> Narrowing_cons (a -> b)) ->
      (Prelude.Int -> Narrowing_cons a) -> Prelude.Int -> Narrowing_cons b;
apply f a d =
  apply_cons
    (\ ps cfs ->
      apply_cons
        (\ psa cas ->
          let {
            shallow = (0 :: Prelude.Int) < d && not (null psa);
            aa = (if shallow then map (\ cf (x : xs) -> cf xs (conv cas x)) cfs
                   else []);
          } in Narrowing_cons
                 (Narrowing_sum_of_products
                   (if shallow
                     then map (\ ab -> Narrowing_sum_of_products psa : ab) ps
                     else []))
                 aa)
        (a (d - (1 :: Prelude.Int))))
    (f d);

cons :: forall a. a -> Prelude.Int -> Narrowing_cons a;
cons a d = Narrowing_cons (Narrowing_sum_of_products [[]]) [(\ _ -> a)];

sum ::
  forall a.
    (Prelude.Int -> Narrowing_cons a) ->
      (Prelude.Int -> Narrowing_cons a) -> Prelude.Int -> Narrowing_cons a;
sum a b d =
  apply_cons
    (\ ssa ca ->
      apply_cons
        (\ ssb cb ->
          Narrowing_cons (Narrowing_sum_of_products (ssa ++ ssb)) (ca ++ cb))
        (a d))
    (b d);

narrowing_nat :: Prelude.Int -> Narrowing_cons Nat;
narrowing_nat = sum (cons Zero_nat) (apply (cons Suc) narrowing_nat);

instance Narrowing Nat where {
  narrowing = narrowing_nat;
};

partial_term_of_nat :: Itself Nat -> Narrowing_term -> Term;
partial_term_of_nat ty (Narrowing_constructor (1 :: Prelude.Int) [a]) =
  App (Const "Nat.Suc"
        (Typerep.Typerep "fun"
          [Typerep.Typerep "Nat.nat" [], Typerep.Typerep "Nat.nat" []]))
    (partial_term_of_nat Type a);
partial_term_of_nat ty (Narrowing_constructor (0 :: Prelude.Int) []) =
  Const "Nat.zero_nat_inst.zero_nat" (Typerep.Typerep "Nat.nat" []);
partial_term_of_nat ty (Narrowing_variable p tt) =
  Free "_" (Typerep.Typerep "Nat.nat" []);

instance Partial_term_of Nat where {
  partial_term_of = partial_term_of_nat;
};

typerep_bool :: Itself Bool -> Typerep.Typerep;
typerep_bool t = Typerep.Typerep "HOL.bool" [];

instance Typerepa Bool where {
  typerep = typerep_bool;
};

narrowing_bool :: Prelude.Int -> Narrowing_cons Bool;
narrowing_bool = sum (cons True) (cons False);

instance Narrowing Bool where {
  narrowing = narrowing_bool;
};

instance Is_testable Bool where {
};

partial_term_of_bool :: Itself Bool -> Narrowing_term -> Term;
partial_term_of_bool ty (Narrowing_constructor (1 :: Prelude.Int) []) =
  Const "HOL.False" (Typerep.Typerep "HOL.bool" []);
partial_term_of_bool ty (Narrowing_constructor (0 :: Prelude.Int) []) =
  Const "HOL.True" (Typerep.Typerep "HOL.bool" []);
partial_term_of_bool ty (Narrowing_variable p tt) =
  Free "_" (Typerep.Typerep "HOL.bool" []);

instance Partial_term_of Bool where {
  partial_term_of = partial_term_of_bool;
};

narrowing_dummy_partial_term_of ::
  forall a. (Partial_term_of a) => Itself a -> Narrowing_term -> Term;
narrowing_dummy_partial_term_of = partial_term_of;

narrowing_dummy_narrowing ::
  forall a. (Narrowing a) => Prelude.Int -> Narrowing_cons a;
narrowing_dummy_narrowing = narrowing;

ensure_testable :: forall a. (Is_testable a) => a -> a;
ensure_testable f =
  let {
    _ = (narrowing_dummy_narrowing :: Prelude.Int -> Narrowing_cons Bool);
    _ = (narrowing_dummy_partial_term_of ::
          Itself Bool -> Narrowing_term -> Term);
    _ = conv;
  } in f;

equal_nat :: Nat -> Nat -> Bool;
equal_nat Zero_nat (Suc x2) = False;
equal_nat (Suc x2) Zero_nat = False;
equal_nat (Suc x2) (Suc y2) = equal_nat x2 y2;
equal_nat Zero_nat Zero_nat = True;

value :: forall a. a -> Nat -> Nat -> Bool;
value dummy = ensure_testable (\ y x -> equal_nat x y);

}
# HG changeset patch
# Parent  a5a09855e4246bfd3d8ccd5b1d80f01479130d75
use explicit selectors in generated haskell code to not rely on accidental lazy 
pattern matching in generated let clauses;
modernized

diff -r a5a09855e424 src/HOL/Quickcheck_Narrowing.thy
--- a/src/HOL/Quickcheck_Narrowing.thy  Fri Jan 20 21:05:11 2017 +0100
+++ b/src/HOL/Quickcheck_Narrowing.thy  Sat Jan 21 16:48:58 2017 +0100
@@ -50,18 +50,24 @@
 datatype (plugins only: code extraction) (dead 'a) narrowing_cons =
   Narrowing_cons narrowing_type "(narrowing_term list \<Rightarrow> 'a) list"
 
-primrec map_cons :: "('a => 'b) => 'a narrowing_cons => 'b narrowing_cons"
-where
-  "map_cons f (Narrowing_cons ty cs) = Narrowing_cons ty (map (\<lambda>c. f o 
c) cs)"
+definition apply_cons :: "(narrowing_type list list \<Rightarrow> 
(narrowing_term list \<Rightarrow> 'a) list \<Rightarrow> 'b) \<Rightarrow> 'a 
narrowing_cons \<Rightarrow> 'b" 
+  where "apply_cons f t =
+    (case t of Narrowing_cons (Narrowing_sum_of_products tyss) cs 
\<Rightarrow> f tyss cs)"
+
+lemma apply_cons [simp, code]:
+  "apply_cons f (Narrowing_cons (Narrowing_sum_of_products tyss) cs) = f tyss 
cs"
+  by (simp add: apply_cons_def)
+
 
 subsubsection \<open>From narrowing's deep representation of terms to @{theory 
Code_Evaluation}'s terms\<close>
 
 class partial_term_of = typerep +
-  fixes partial_term_of :: "'a itself => narrowing_term => 
Code_Evaluation.term"
+  fixes partial_term_of :: "'a itself \<Rightarrow> narrowing_term 
\<Rightarrow> Code_Evaluation.term"
 
 lemma partial_term_of_anything: "partial_term_of x nt \<equiv> t"
   by (rule eq_reflection) (cases "partial_term_of x nt", cases t, simp)
  
+
 subsubsection \<open>Auxilary functions for Narrowing\<close>
 
 consts nth :: "'a list => integer => 'a"
@@ -80,48 +86,39 @@
 
 code_printing constant marker \<rightharpoonup> (Haskell_Quickcheck) "''\\0'"
 
+  
 subsubsection \<open>Narrowing's basic operations\<close>
 
-type_synonym 'a narrowing = "integer => 'a narrowing_cons"
+type_synonym 'a narrowing = "integer \<Rightarrow> 'a narrowing_cons"
 
 definition empty :: "'a narrowing"
-where
-  "empty d = Narrowing_cons (Narrowing_sum_of_products []) []"
+  where "empty d = Narrowing_cons (Narrowing_sum_of_products []) []"
   
-definition cons :: "'a => 'a narrowing"
-where
-  "cons a d = (Narrowing_cons (Narrowing_sum_of_products [[]]) [(\<lambda>_. 
a)])"
+definition cons :: "'a \<Rightarrow> 'a narrowing"
+  where "cons a d = (Narrowing_cons (Narrowing_sum_of_products [[]]) 
[(\<lambda>_. a)])"
 
-fun conv :: "(narrowing_term list => 'a) list => narrowing_term => 'a"
-where
-  "conv cs (Narrowing_variable p _) = error (marker # map toEnum p)"
-| "conv cs (Narrowing_constructor i xs) = (nth cs i) xs"
+primrec conv :: "(narrowing_term list \<Rightarrow> 'a) list \<Rightarrow> 
narrowing_term \<Rightarrow> 'a"
+  where "conv cs (Narrowing_variable p _) = error (marker # map toEnum p)"
+      | "conv cs (Narrowing_constructor i xs) = (nth cs i) xs"
 
-fun non_empty :: "narrowing_type => bool"
-where
-  "non_empty (Narrowing_sum_of_products ps) = (\<not> (List.null ps))"
+definition "apply" :: "('a \<Rightarrow> 'b) narrowing \<Rightarrow> 'a 
narrowing \<Rightarrow> 'b narrowing"
+  where "apply f a d = apply_cons (\<lambda>ps cfs.
+    apply_cons (\<lambda>ps' cas.
+      (let
+        shallow = d > 0 \<and> ps' \<noteq> [];
+        cs = [(\<lambda>xs'. (case xs' of x # xs => cf xs (conv cas x))). 
shallow, cf <- cfs]
+      in Narrowing_cons (Narrowing_sum_of_products [Narrowing_sum_of_products 
ps' # p. shallow, p <- ps]) cs))
+      (a (d - 1))) (f d)"
 
-definition "apply" :: "('a => 'b) narrowing => 'a narrowing => 'b narrowing"
-where
-  "apply f a d =
-     (case f d of Narrowing_cons (Narrowing_sum_of_products ps) cfs =>
-       case a (d - 1) of Narrowing_cons ta cas =>
-       let
-         shallow = (d > 0 \<and> non_empty ta);
-         cs = [(\<lambda>xs'. (case xs' of [] => undefined | x # xs => cf xs 
(conv cas x))). shallow, cf <- cfs]
-       in Narrowing_cons (Narrowing_sum_of_products [ta # p. shallow, p <- 
ps]) cs)"
-
-definition sum :: "'a narrowing => 'a narrowing => 'a narrowing"
-where
-  "sum a b d =
-    (case a d of Narrowing_cons (Narrowing_sum_of_products ssa) ca => 
-      case b d of Narrowing_cons (Narrowing_sum_of_products ssb) cb =>
-      Narrowing_cons (Narrowing_sum_of_products (ssa @ ssb)) (ca @ cb))"
+definition sum :: "'a narrowing \<Rightarrow> 'a narrowing \<Rightarrow> 'a 
narrowing"
+  where "sum a b d = apply_cons (\<lambda>ssa ca.
+    apply_cons (\<lambda>ssb cb. Narrowing_cons (Narrowing_sum_of_products 
(ssa @ ssb)) (ca @ cb))
+     (a d)) (b d)"
 
 lemma [fundef_cong]:
   assumes "a d = a' d" "b d = b' d" "d = d'"
   shows "sum a b d = sum a' b' d'"
-using assms unfolding sum_def by (auto split: narrowing_cons.split 
narrowing_type.split)
+  using assms unfolding sum_def by (auto split: narrowing_cons.split 
narrowing_type.split)
 
 lemma [fundef_cong]:
   assumes "f d = f' d" "(\<And>d'. 0 \<le> d' \<and> d' < d \<Longrightarrow> 
a d' = a' d')"
@@ -132,10 +129,11 @@
   moreover have "0 < d' \<Longrightarrow> 0 \<le> d' - 1"
     by (simp add: less_integer_def less_eq_integer_def)
   ultimately show ?thesis
-    by (auto simp add: apply_def Let_def
+    by (auto simp add: apply_def Let_def apply_cons_def
       split: narrowing_cons.split narrowing_type.split)
 qed
 
+  
 subsubsection \<open>Narrowing generator type class\<close>
 
 class narrowing =
@@ -155,6 +153,7 @@
 where
   "all f = (case narrowing (100 :: integer) of Narrowing_cons ty cs => 
Universal ty (\<lambda>t. f (conv cs t)) (partial_term_of (TYPE('a))))"
 
+  
 subsubsection \<open>class \<open>is_testable\<close>\<close>
 
 text \<open>The class \<open>is_testable\<close> ensures that all necessary 
type instances are generated.\<close>
@@ -193,6 +192,7 @@
 hide_type (open) cfun
 hide_const (open) Constant eval_cfun Abs_cfun Rep_cfun
 
+  
 subsubsection \<open>Setting up the counterexample generator\<close>
 
 ML_file "Tools/Quickcheck/narrowing_generators.ML"
@@ -213,6 +213,7 @@
       z = (conv :: _ => _ => unit)  in f)"
 unfolding Let_def ensure_testable_def ..
 
+  
 subsection \<open>Narrowing for sets\<close>
 
 instantiation set :: (narrowing) narrowing
@@ -224,6 +225,7 @@
 
 end
   
+  
 subsection \<open>Narrowing for integers\<close>
 
 
@@ -263,8 +265,7 @@
 
 end
 
-lemma [code, code del]: "partial_term_of (ty :: int itself) t \<equiv> 
undefined"
-  by (rule partial_term_of_anything)+
+declare [[code drop: "partial_term_of :: int itself \<Rightarrow> _"]]
 
 lemma [code]:
   "partial_term_of (ty :: int itself) (Narrowing_variable p t) \<equiv>
@@ -273,7 +274,7 @@
     (if i mod 2 = 0
      then Code_Evaluation.term_of (- (int_of_integer i) div 2)
      else Code_Evaluation.term_of ((int_of_integer i + 1) div 2))"
-  by (rule partial_term_of_anything)+
+  by (fact partial_term_of_anything)+
 
 instantiation integer :: narrowing
 begin
@@ -286,8 +287,7 @@
 
 end
 
-lemma [code, code del]: "partial_term_of (ty :: integer itself) t \<equiv> 
undefined"
-  by (rule partial_term_of_anything)+
+declare [[code drop: "partial_term_of :: integer itself \<Rightarrow> _"]]
 
 lemma [code]:
   "partial_term_of (ty :: integer itself) (Narrowing_variable p t) \<equiv>
@@ -319,15 +319,17 @@
            (Generated'_Code.Const \"Groups.uminus'_class.uminus\" (mkFunT t t))
            (mkNumber (- i)); } in mkNumber)"
 
+  
 subsection \<open>The \<open>find_unused_assms\<close> command\<close>
 
 ML_file "Tools/Quickcheck/find_unused_assms.ML"
 
+  
 subsection \<open>Closing up\<close>
 
 hide_type narrowing_type narrowing_term narrowing_cons property
-hide_const map_cons nth error toEnum marker empty Narrowing_cons conv 
non_empty ensure_testable all exists drawn_from around_zero
+hide_const nth error toEnum marker empty Narrowing_cons conv ensure_testable 
all exists drawn_from around_zero apply_cons
 hide_const (open) Narrowing_variable Narrowing_constructor "apply" sum cons
-hide_fact empty_def cons_def conv.simps non_empty.simps apply_def sum_def 
ensure_testable_def all_def exists_def
+hide_fact empty_def cons_def conv.simps apply_def sum_def ensure_testable_def 
all_def exists_def
 
 end
# HG changeset patch
# Parent  65a2474441004d3db26b0c4343f023d131a00c94
for generated Haskell code, never use let-binds with pattern matching: 
irrefutable patterns destroy partial correctness

diff -r 65a247444100 src/Tools/Code/code_haskell.ML
--- a/src/Tools/Code/code_haskell.ML    Wed Jan 11 16:43:31 2017 +0100
+++ b/src/Tools/Code/code_haskell.ML    Wed Jan 11 20:51:37 2017 +0100
@@ -103,14 +103,14 @@
     and print_bind tyvars some_thm fxy p = gen_print_bind (print_term tyvars) 
some_thm fxy p
     and print_case tyvars some_thm vars fxy { clauses = [], ... } =
           (brackify fxy o Pretty.breaks o map str) ["error", "\"empty case\""]
-      | print_case tyvars some_thm vars fxy (case_expr as { clauses = [_], ... 
}) =
+      | print_case tyvars some_thm vars fxy (case_expr as { clauses = [(IVar 
_, _)], ... }) =
           let
-            val (binds, body) = Code_Thingol.unfold_let (ICase case_expr);
-            fun print_match ((pat, _), t) vars =
+            val (vs, body) = Code_Thingol.unfold_let_no_pat (ICase case_expr);
+            fun print_assignment ((some_v, _), t) vars =
               vars
-              |> print_bind tyvars some_thm BR pat
+              |> print_bind tyvars some_thm BR (IVar some_v)
               |>> (fn p => semicolon [p, str "=", print_term tyvars some_thm 
vars NOBR t])
-            val (ps, vars') = fold_map print_match binds vars;
+            val (ps, vars') = fold_map print_assignment vs vars;
           in brackify_block fxy (str "let {")
             ps
             (concat [str "}", str "in", print_term tyvars some_thm vars' NOBR 
body])
@@ -451,9 +451,9 @@
     fun dest_monad (IConst { sym = Constant c, ... } `$ t1 `$ t2) =
           if c = c_bind then dest_bind t1 t2
           else NONE
-      | dest_monad t = case Code_Thingol.split_let t
-         of SOME (((pat, ty), tbind), t') =>
-              SOME ((SOME ((pat, ty), false), tbind), t')
+      | dest_monad t = case Code_Thingol.split_let_no_pat t
+         of SOME (((some_v, ty), tbind), t') =>
+              SOME ((SOME ((IVar some_v, ty), false), tbind), t')
           | NONE => NONE;
     val implode_monad = Code_Thingol.unfoldr dest_monad;
     fun print_monad print_bind print_term (NONE, t) vars =
diff -r 65a247444100 src/Tools/Code/code_thingol.ML
--- a/src/Tools/Code/code_thingol.ML    Wed Jan 11 16:43:31 2017 +0100
+++ b/src/Tools/Code/code_thingol.ML    Wed Jan 11 20:51:37 2017 +0100
@@ -47,7 +47,9 @@
   val unfold_app: iterm -> iterm * iterm list
   val unfold_abs: iterm -> (vname option * itype) list * iterm
   val split_let: iterm -> (((iterm * itype) * iterm) * iterm) option
+  val split_let_no_pat: iterm -> (((string option * itype) * iterm) * iterm) 
option
   val unfold_let: iterm -> ((iterm * itype) * iterm) list * iterm
+  val unfold_let_no_pat: iterm -> ((string option * itype) * iterm) list * 
iterm
   val split_pat_abs: iterm -> ((iterm * itype) * iterm) option
   val unfold_pat_abs: iterm -> (iterm * itype) list * iterm
   val unfold_const_app: iterm -> (const * iterm list) option
@@ -184,8 +186,14 @@
   (fn ICase { term = t, typ = ty, clauses = [(p, body)], ... } => SOME (((p, 
ty), t), body)
     | _ => NONE);
 
+val split_let_no_pat = 
+  (fn ICase { term = t, typ = ty, clauses = [(IVar v, body)], ... } => SOME 
(((v, ty), t), body)
+    | _ => NONE);
+
 val unfold_let = unfoldr split_let;
 
+val unfold_let_no_pat = unfoldr split_let_no_pat;
+
 fun unfold_const_app t =
  case unfold_app t
   of (IConst c, ts) => SOME (c, ts)

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
isabelle-dev mailing list
isabelle-...@in.tum.de
https://mailmanbroy.informatik.tu-muenchen.de/mailman/listinfo/isabelle-dev

Reply via email to