Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/Isabelle/Archive-of-Formal-Proofs/thys/PCF/   (Sammlung formaler Beweise Version 2026-5©)  Datei vom 31.4.2026 mit Größe 45 kB image not shown  

SSL PCF.thy

  Sprache: Isabelle
 

(*  Title:      PCF.thy
    Author:     Peter Gammie
*)


section Logical relations for definability in PCF
(*<*)

theory PCF
imports
  Basis
  Logical_Relations
begin

(*>*)
text

 label{sec:directsem}

  this machinery we can demonstrate some classical results about
  🍋"Plotkin77". We diverge from the traditional treatment by
  PCF as an untyped language and including both call-by-name
 CBN) and call-by-value (CBV) abstractions following
 🍋"DBLP:conf/icalp/Reynolds74". We also adopt some of the
  of 🍋Chapter~11 in "Winskel:1993", in particular by
  the fixed point operator a binding construct.

  model the syntax of PCF as a HOL datatype, where variables have
  drawn from the naturals:

 


type_synonym var = nat

datatype expr =
    Var var
  | App expr expr
  | AbsN var expr (* non-strict fns *)
  | AbsV var expr (* strict fns *)
  | Diverge (Ω)
  | Fix var expr
  | tt
  | ff
  | Cond expr expr expr
  | Num nat
  | Succ expr
  | Pred expr
  | IsZero expr

subsectionDirect denotational semantics

text

 label{sec:densem}

  give this language a direct denotational semantics by interpreting
  into a domain of values.

 


domain ValD =
   ValF (lazy appF :: "ValD ValD")
 | ValTT | ValFF
 | ValN (lazy "nat")

text

  \textbf{lazy} keyword means that the @{term "ValF"} constructor is
 , i.e. @{term "ValF "}, which further means that @{term
 ValF(Λ x. ) "}.

  naturals are discretely ordered.

 

(*<*)

lemma ValD_case_ID [simp]:
  "ValD_caseValFValTTValFFValN = ID"
  apply (rule cfun_eqI)
  apply (case_tac x)
  apply simp_all
  done

lemma below_monic_ValF [iff]:
  "below_monic_cfun ValF"
  by (rule below_monicI) simp

lemma below_monic_ValN [iff]:
  "below_monic_cfun ValN"
  by (rule below_monicI) simp

(*>*)
text

  minimal invariant for @{typ "ValD"} is straightforward; the
  @{term "cfun_mapfgh"} denotes @{term "g oo h oo f"}.

 


fixrec
  ValD_copy_rec :: "(ValD ValD) (ValD ValD)"
where
  "ValD_copy_recr(ValFf) = ValF(cfun_maprrf)"
"ValD_copy_recr(ValTT) = ValTT"
"ValD_copy_recr(ValFF) = ValFF"
"ValD_copy_recr(ValNn) = ValNn"
(*<*)

lemma ValD_copy_rec_strict [simp]:
  "ValD_copy_recr = "
  by fixrec_simp

abbreviation
  "ValD_copy fixValD_copy_rec"

lemma ValD_copy_strict [simp]:
  "ValD_copy = "
  by (subst fix_eq) simp

lemma ValD_copy_ID [simp]:
  "ValD_copy = ID"
proof -
  { fix x :: ValD
    fix i :: nat
    have "ValD_take i(ValD_copy(ValD_take ix)) = ValD_take ix"
    proof (induct i arbitrary: x)
      case (Suc n) then show ?case
        by (cases x) (subst fix_eq, simp add: cfun_map_def)+
    qed simp }
  then have "x :: ValD. (i. ValD_take i(ValD_copy(ValD_take ix))) = (i. ValD_take ix)"
    by (blast intro: lub_eq)
  then show ?thesis by (simp add: lub_distribs ValD.lub_take cfun_eq_iff)
qed

(*>*)
text

  interpret the PCF constants in the obvious ways. ``Ill-typed'' uses
  these combinators are mapped to @{term ""}.

 


definition cond :: "ValD ValD ValD ValD" where
  "cond Λ i t e. case i of ValFf ==> | ValTT ==> t | ValFF ==> e | ValNn ==> "

definition succ :: "ValD ValD" where
  "succ Λ (ValNn). ValN(n + 1)"

definition pred :: "ValD ValD" where
  "pred Λ (ValNn). case n of 0 ==> | Suc n ==> ValNn"

definition isZero :: "ValD ValD" where
  "isZero Λ (ValNn). if n = 0 then ValTT else ValFF"

text

  model environments simply as continuous functions from variable
  to values.

 


type_synonym Var = "var"
type_synonym 'a Env = "Var 'a"

definition env_empty :: "'a Env" where
  "env_empty "

definition env_ext :: "Var 'a 'a Env 'a Env" where
  "env_ext Λ v x ρ v'. if v = v' then x else ρv'"
(*<*)

lemma env_ext_same: "env_extvxρv = x"
  by (simp add: env_ext_def)

lemma env_ext_neq: "v v' ==> env_extvxρv' = ρv'"
  by (simp add: env_ext_def)

lemmas env_ext_simps[simp] = env_ext_same env_ext_neq

(*>*)
text

  semantics is given by a function defined by primitive recursion
  the syntax.

 


type_synonym EnvD = "ValD Env"

primrec
  evalD :: "expr ==> EnvD ValD"
where
  "evalD (Var v) = (Λ ρ. ρv)"
"evalD (App f x) = (Λ ρ. appF(evalD fρ)(evalD xρ))"
"evalD (AbsN v e) = (Λ ρ. ValF(Λ x. evalD e(env_extvxρ)))"
"evalD (AbsV v e) = (Λ ρ. ValF(strictify(Λ x. evalD e(env_extvxρ))))"
"evalD (Diverge) = (Λ ρ. )"
"evalD (Fix v e) = (Λ ρ. μ x. evalD e(env_extvxρ))"
"evalD (tt) = (Λ ρ. ValTT)"
"evalD (ff) = (Λ ρ. ValFF)"
"evalD (Cond i t e) = (Λ ρ. cond(evalD iρ)(evalD tρ)(evalD eρ))"
"evalD (Num n) = (Λ ρ. ValNn)"
"evalD (Succ e) = (Λ ρ. succ(evalD eρ))"
"evalD (Pred e) = (Λ ρ. pred(evalD eρ))"
"evalD (IsZero e) = (Λ ρ. isZero(evalD eρ))"

abbreviation eval' :: "expr ==> ValD Env ==> ValD" ([_]_ [0,100060where
  "eval' M ρ evalD Mρ"


subsectionThe Y Combinator

text

  can shown the Y combinator is the least fixed point operator using
  the minimal invariant. In other words, @{term "fix"} is
  in untyped PCF minus the @{term "Fix"} construct.

  is Example~3.6 from 🍋"PittsAM:relpod". He attributes the
  to Plotkin.

  two functions are Δ λf x. f (x x) and Y
 λf. (Δ f) (Δ f)
.

  the numbers here are names, not de Bruijn indices.

 


definition Y_delta :: expr where
  "Y_delta AbsN 0 (AbsN 1 (App (Var 0) (App (Var 1) (Var 1))))"

definition Ycomb :: expr where
  "Ycomb AbsN 0 (App (App Y_delta (Var 0)) (App Y_delta (Var 0)))"

definition fixD :: "ValD ValD" where
  "fixD Λ (ValFf). fixf"

lemma Y: "[Ycomb]ρ = ValFfixD"
(*<*)
proof(rule below_antisym)
  show "ValFfixD [Ycomb]ρ"
    unfolding fixD_def Ycomb_def
    apply (clarsimp simp: cfun_below_iff eta_cfun)
    apply (case_tac x)
     apply simp_all
    apply (rule fix_least)
    by (subst Y_delta_def, simp)
next
  { fix f ρ
    let ?P = "λx. x ID appF(x(appF([Y_delta]ρ)(ValFf)))(appF([Y_delta]ρ)(ValFf)) fixD(ValFf)"
    have "?P ValD_copy"
      apply (rule fix_ind)
        apply simp
       apply simp
      apply clarsimp
      apply (rule conjI)
       apply (rule cfun_belowI)
       apply (case_tac xa)
        apply simp_all
       apply (drule cfun_map_below_ID)
       apply (simp add: cfun_below_iff)
      apply (simp add: fixD_def eta_cfun)
      apply (subst Y_delta_def)
      apply (subst fix_eq)
      apply simp
      apply (rule cfun_below_ID, assumption)
      apply (rule monofun_cfun_arg)
      apply (subgoal_tac "appF(x(appF([Y_delta]ρ)(ValFf)))(x(appF([Y_delta]ρ)(ValFf)))
                         appF(x(appF([Y_delta]ρ)(ValFf)))(appF([Y_delta]ρ)(ValFf))")
       apply (erule (1) below_trans)
      apply (simp add: monofun_cfun_arg cfun_below_iff)
      done }
  then show "[Ycomb]ρ ValFfixD"
    unfolding Ycomb_def fixD_def
    apply (clarsimp simp: cfun_below_iff)
    apply (case_tac x)
    apply (subst Y_delta_def, simp)
    apply simp
    apply (subst Y_delta_def, simp)+
    done
qed

(* FIXME could also try to show uniformity, cf Gunter, Plotkin "3 Inadequate Models". *)

(*>*)

subsectionLogical relations for definability

text

 label{sec:pcfdefinability}

  element of @{typ "ValD"} is definable if there is an expression
  denotes it.

 


definition definable :: "ValD ==> bool" where
  "definable d M. [M]env_empty = d"

text

  classical result about PCF is that while the denotational semantics
  \emph{adequate}, as we show in \S\ref{sec:opsem}, it is not
 emph{fully abstract}, i.e. it contains undefinable values (junk).

  way of showing this is to reason operationally; see, for instance,
 🍋\S4 in "Plotkin77" and 🍋\S6.1 in "Gunter:1992".

  is to use \emph{logical relations}, following
 🍋"Plotkin:1973", and also
 🍋"Mitchell:1996" and "Sieber:1992" and "DBLP:conf/mfps/Stoughton93".

  this purpose we define a logical relation to be a set of vectors
  @{typ "ValD"} that is closed under continuous functions of type
 {typ "ValD ValD"}. This is complicated by the @{term "ValF"} tag
  having strict function abstraction.

 


definition
  logical_relation :: "('i::type ==> ValD) set ==> bool"
where
  "logical_relation R
     (fs R. xs R. (λj. appF(fs j)(xs j)) R)
    (fs R. xs R. (λj. strictify(appF(fs j))(xs j)) R)
    (fs. (xs R. (λj. (fs j)(xs j)) R) (λj. ValF(fs j)) R)
    (fs. (xs R. (λj. strictify(fs j)(xs j)) R) (λj. ValF(strictify(fs j))) R)
    (xs R. (λj. fixD(xs j)) R)
    (cs R. ts R. es R. (λj. cond(cs j)(ts j)(es j)) R)
    (xs R. (λj. succ(xs j)) R)
    (xs R. (λj. pred(xs j)) R)
    (xs R. (λj. isZero(xs j)) R)"
(*<*)

lemma logical_relationI:
  "[ fs xs. [ fs R; xs R ] ==> (λj. appF(fs j)(xs j)) R;
     fs xs. [ fs R; xs R ] ==> (λj. strictify(appF(fs j))(xs j)) R;
     fs. (xs. xs R ==> (λj. (fs j)(xs j)) R) ==> (λj. ValF(fs j)) R;
     fs. (xs. xs R ==> (λj. strictify(fs j)(xs j)) R) ==> (λj. ValF(strictify(fs j))) R;
     xs. xs R ==> (λj. fixD(xs j)) R;
     cs ts es. [ cs R; ts R; es R ] ==> (λj. cond(cs j)(ts j)(es j)) R;
     xs. xs R ==> (λj. succ(xs j)) R;
     xs. xs R ==> (λj. pred(xs j)) R;
     xs. xs R ==> (λj. isZero(xs j)) R ] ==> logical_relation R"
  unfolding logical_relation_def by (simp add: cfcomp1)

lemma lr_l2r:
  "[ fs R; xs R; logical_relation R ] ==> (λj. appF(fs j)(xs j)) R"
  "[ fs R; xs R; logical_relation R ] ==> (λj. strictify(appF(fs j))(xs j)) R"
  "[ xs R; logical_relation R ] ==> (λj. fixD(xs j)) R"
  "[ cs R; ts R; es R; logical_relation R ] ==> (λj. cond(cs j)(ts j)(es j)) R"
  "[ xs R; logical_relation R ] ==> (λj. succ(xs j)) R"
  "[ xs R; logical_relation R ] ==> (λj. pred(xs j)) R"
  "[ xs R; logical_relation R ] ==> (λj. isZero(xs j)) R"
  unfolding logical_relation_def by blast+

lemma lr_r2l:
  "[ logical_relation R; xs R. (λj. (fs j)(xs j)) R ] ==> (λi. ValF(fs i)) R"
  unfolding logical_relation_def by (simp add: cfcomp1)

lemma lr_r2l_strict:
  "[ logical_relation R; xs R. (λj. strictify(fs j)(xs j)) R ] ==> (λi. ValF(strictify(fs i))) R"
  unfolding logical_relation_def by (simp add: cfcomp1)

(*>*)
text

  the context of PCF these relations also need to respect the
 .

 


definition
  PCF_consts_rel :: "('i::type ==> ValD) set ==> bool"
where
  "PCF_consts_rel R
        R
      (λi. ValTT) R
      (λi. ValFF) R
      (n. (λi. ValNn) R)"
(*<*)

lemma PCF_consts_rel_simps [simp, elim]:
  "PCF_consts_rel R ==> R"
  "PCF_consts_rel R ==> (λi. ValTT) R"
  "PCF_consts_rel R ==> (λi. ValFF) R"
  "PCF_consts_rel R ==> (λi. ValNn) R"
unfolding PCF_consts_rel_def by simp_all

lemma PCF_consts_relI:
  "[ R;
     (λi. ValTT) R;
     (λi. ValFF) R;
     n. (λi. ValNn) R ] ==> PCF_consts_rel R"
unfolding PCF_consts_rel_def by blast

(*>*)
text

abbreviation
  "PCF_lr R adm (λx. x R) logical_relation R PCF_consts_rel R"

text

  fundamental property of logical relations states that all PCF
  satisfy all PCF logical relations. This result is
  due to 🍋"Plotkin:1973". The proof is by a
  induction on the expression @{term "M"}.

 


lemma lr_fundamental:
  assumes lr: "PCF_lr R"
  assumes ρ: "v. (λi. ρ iv) R"
  shows "(λi. [M](ρ i)) R"
(*<*)
using ρ
proof(induct M arbitrary: ρ)
  case (Var v ρ) then show ?case by simp
next
  case (App e1 e2 ρ)
  with lr lr_l2r(1)[where fs="λj. [e1](ρ j)" and xs="λj. [e2](ρ j)"]
  show ?case by simp
next
  case (AbsN v e)
  with lr show ?case
    apply clarsimp
    apply (erule lr_r2l[where fs="λi. Λ x. [e](env_extvx(ρ i))" and R=R, simplified])
    apply clarsimp
    apply (cut_tac ρ="λj. env_extv(xs j)(ρ j)" in AbsN.hyps)
     apply (simp add: env_ext_def)
     using AbsN(2)
     apply clarsimp
     apply (case_tac "v=va")
      apply (simp add: eta_cfun)
     apply simp
    apply simp
    done
next
  case (AbsV v e)
  with lr show ?case
    apply clarsimp
    apply (rule lr_r2l_strict[where fs="λi. Λ x. [e](env_extvx(ρ i))", simplified])
     apply simp
    apply clarsimp
    apply (cut_tac fs="λi. ValF(Λ x. [e](env_extvx(ρ i)))" and xs=xs and R=R in lr_l2r(2))
     apply simp_all
    apply (erule lr_r2l[where fs="λi. Λ x. [e](env_extvx(ρ i))" and R=R, simplified])
    apply clarsimp
    apply (cut_tac ρ="λj. env_extv(xsa j)(ρ j)" in AbsV.hyps)
     apply (simp add: env_ext_def)
     using AbsV(2)
     apply clarsimp
     apply (case_tac "v=va")
      apply (simp add: eta_cfun)
     apply simp
    apply simp
    done
next
  case (Fix v e ρ) show ?case
    apply simp
    apply (subst fix_argument_promote_fun)
    apply (rule fix_ind[where F="Λ f. (λx. (Λ xa. [e](env_extvxa(ρ x)))(f x))"])
      apply (simp add: lr)
     apply (simp add: lr inst_fun_pcpo[symmetric])
    apply simp
    apply (cut_tac ρ="λi. env_extv(x i)(ρ i)" in Fix.hyps)
     unfolding env_ext_def
     using Fix(2)
     apply clarsimp
     apply (case_tac "v=va")
      apply (simp add: eta_cfun)
     apply simp
    apply (simp add: cont_fun)
    done
next
  case (Cond i t e ρ)
  with lr lr_l2r(4)[where cs="λj. [i](ρ j)" and ts="λj. [t](ρ j)" and es="λj. [e](ρ j)"]
  show ?case by simp
next
  case (Succ e ρ)
  with lr lr_l2r(5)[where xs="λj. [e](ρ j)"]
  show ?case by simp
next
  case (Pred e ρ)
  with lr lr_l2r(6)[where xs="λj. [e](ρ j)"]
  show ?case by simp
next
  case (IsZero e ρ)
  with lr lr_l2r(7)[where xs="λj. [e](ρ j)"]
  show ?case by simp
next
  case Diverge with lr show ?case
    apply simp
    apply (simp add: inst_fun_pcpo[symmetric])
    done
qed (insert lr, simp_all)
(*>*)

text

  can use this result to show that there is no PCF term that maps the
  @{term "args R"} to @{term "result R"} for some logical
  @{term "R"}. If we further show that there is a function
 {term "f"} in @{term "ValD"} such that @{term "f args = result"} then
  can conclude that @{term "f"} is not definable.

 


abbreviation
  appFLv :: "ValD ==> ('i::type ==> ValD) list ==> ('i ==> ValD)"
where
  "appFLv f args (λi. foldl (λf x. appFf(x i)) f args)"

lemma lr_appFLv:
  assumes lr: "logical_relation R"
  assumes f: "(λi::'i::type. f) R"
  assumes args: "set args R"
  shows "appFLv f args R"
(*<*)
using args
proof(induct args rule: rev_induct)
  case Nil with f show ?case by simp
next
  case (snoc x xs) then show ?case
    using lr_l2r(1)[OF _ _ lr, where fs="λi. (foldl (λf x. appFf(x i)) f xs)" and xs=x]
    by simp
qed

(*>*)
text

corollary not_definable:
  fixes R :: "('i::type ==> ValD) set"
  fixes args :: "('i ==> ValD) list"
  fixes result :: "'i ==> ValD"
  assumes lr: "PCF_lr R"
  assumes args: "set args R"
  assumes result: "result R"
  shows "¬((f::ValD). definable f appFLv f args = result)"
(*<*)
proof
  assume "f. definable f appFLv f args = result"
  then obtain f
    where df: "definable f"
      and f: "appFLv f args = result" by blast
  from df obtain M
    where Mf: "[M]env_empty = f"
    unfolding definable_def by blast
  with lr lr_fundamental[OF lr, where M=M and ρ="λi. env_empty"]
       f args lr_appFLv[where f=f and R=R and args=args]
  have "result R" unfolding env_empty_def by (simp add: inst_fun_pcpo[symmetric])
  with result show False ..
qed
(*>*)

subsectionParallel OR is not definable

text 

 label{sec:por}

  show that parallel-or is not λ-definable following
 🍋"Sieber:1992" and 🍋"DBLP:conf/mfps/Stoughton93".

 -or is similar to the familiar short-circuting or except that
  the first argument is @{term ""} and the second one is
 {term "ValTT"}, we get @{term "ValTT"} (and not @{term
 "}). It is continuous and then have included in the @{typ
 ValD"} domain.

 


definition por :: "ValD ==> ValD ==> ValD" (_ por _ [31,3030where
  "x por y
     if x = ValTT then ValTT
       else if y = ValTT then ValTT
              else if (x = ValFF y = ValFF) then ValFF else "

textThe defining properties of parallel-or.

lemma POR_simps [simp]:
  "(ValTT por y) = ValTT"
  "(x por ValTT) = ValTT"
  "(ValFF por ValFF) = ValFF"
  "(ValFF por ) = "
  "(ValFF por ValNn) = "
  "(ValFF por ValFf) = "
  "( por ValFF) = "
  "(ValNn por ValFF) = "
  "(ValFf por ValFF) = "
  "( por ) = "
  "( por ValNn) = "
  "( por ValFf) = "
  "(ValNn por ) = "
  "(ValFf por ) = "
  "(ValNm por ValNn) = "
  "(ValNn por ValFf) = "
  "(ValFf por ValNn) = "
  "(ValFf por ValFg) = "
  unfolding por_def by simp_all
(*<*)

text

  show that parallel-or is a continuous function.

 


lemma POR_sym: "(x por y) = (y por x)"
  unfolding por_def by simp

lemma ValTT_below_iff [simp]: "ValTT x x = ValTT"
  by (cases x) simp_all

lemma ValFF_below_iff [simp]: "ValFF x x = ValFF"
  by (cases x) simp_all

lemma monofun_por: "monofun (λx. x por y)"
  unfolding por_def
  by (rule monofunI) auto

lemma mic2mic: "max_in_chain i Y ==> max_in_chain i (λi. f (Y i))"
  unfolding max_in_chain_def by simp

lemma cont_por1: "cont (λx. x por y)"
  apply (rule contI2[OF monofun_por])
  apply (case_tac "Lub Y")
   apply simp_all
   apply (cases y)
   apply simp_all
   apply (cases y)
   apply simp_all

   apply (frule compact_imp_max_in_chain)
    apply simp
   apply clarsimp
   apply (frule mic2mic[where f="λx. x por y"])
   apply (subst iffD1[OF maxinch_is_thelub])
   apply simp_all
   apply (simp_all add: maxinch_is_thelub)

   apply (frule compact_imp_max_in_chain)
    apply simp
   apply clarsimp
   apply (frule mic2mic[where f="λx. x por y"])
   apply (subst iffD1[OF maxinch_is_thelub])
   apply simp_all
   apply (simp_all add: maxinch_is_thelub)

   apply (cases y)
   apply simp_all
   done

lemma cont_por[cont2cont, simp]:
  assumes f: "cont (λx. f x)" and g: "cont (λx. g x)"
  shows "cont (λx. f x por g x)"
proof -
  have A: "f y. cont f ==> cont (λx. f x por y)"
    by (rule cont_apply) (simp_all add: cont_por1)
  from A[OF f] A[OF g] show ?thesis
    by (auto simp: cont_por1 POR_sym intro: cont_apply[OF f])
qed

(*>*)
text

  need three-element vectors.

 


datatype Three = One | Two | Three

text

  standard logical relation @{term "R"} that demonstrates POR is not
  is:
 [
 (x, y, z) \in R\mbox{iff}x = y = z \lor (x = \bot \lor y = \bot)
 ]
  POR satisfies this relation can be seen from its truth table (see
 ).

  we restrict the x = y = z clause to non-function
 . Adding functions breaks the ``logical relations'' property.

 


definition
  POR_base_lf_rep :: "(Three ==> ValD) lf_rep"
where
  "POR_base_lf_rep λ(mR, pR).
     { (λi. ValTT) } { (λi. ValFF) } ― x = y = z for bools
    (n. { (λi. ValNn) }) ― x = y = z for numerals
    { f . f One = } ― x =
    { f . f Two = } ― y = "

text

We close this relation with respect to continuous functions. This
functor yields an admissible relation for all @{term " "} and is
 .

 

definition
  fn_lf_rep :: "('i::type ==> ValD) lf_rep"
where
  "fn_lf_rep λ(mR, pR). { λi. ValF(fs i) |fs. xs unlr (undual mR). (λj. (fs j)(xs j)) unlr pR }"
(*<*)

lemma adm_POR_base_lf_rep:
  "adm (λx. x POR_base_lf_rep r)"
unfolding POR_base_lf_rep_def
using adm_below_monic_exists[OF _ below_monic_fun_K[where f="ValN"], where P="λ_. True", simplified]
by (auto intro!: adm_disj simp: cont_fun)

lemma mono_POR_base_lf_rep:
  "mono POR_base_lf_rep"
unfolding POR_base_lf_rep_def by (blast intro!: monoI)

lemma adm_fn:
  shows "adm (λx. x fn_lf_rep r)"
unfolding fn_lf_rep_def
using adm_below_monic_exists[OF _ below_monic_fun_K[where f="ValF"], where P="λ_. True", simplified]
apply (clarsimp simp: split_def)
apply (rule adm_below_monic_exists)
apply (auto simp: cont_fun below_monic_indexed)
done

(*
  by (fastforce simp: split_def intro: adm_below_monic_exists)
*)


lemma mono_fn_lf_rep:
  "mono fn_lf_rep"
proof
  fix x y :: "('a ==> ValD) admS dual × ('a ==> ValD) admS"
  obtain x1 x2 y1 y2 where [simp]: "x = (x1, x2)" "y = (y1, y2)"
    by (cases x, cases y)
  assume "x y"
  then show "fn_lf_rep x fn_lf_rep y"
    by (simp add: fn_lf_rep_def) (use dual_less_eq_iff less_eq_admS_def in blast)
qed

(*>*)
text

definition POR_lf_rep :: "(Three ==> ValD) lf_rep" where
  "POR_lf_rep R POR_base_lf_rep R fn_lf_rep R"

abbreviation "POR_lf λr. mklr (POR_lf_rep r)"
(*<*)

lemma admS_POR_lf [intro, simp]:
  "POR_lf_rep r admS"
proof
  show " POR_lf_rep r"
    unfolding POR_lf_rep_def POR_base_lf_rep_def
    by simp
next
  show "adm (λx. x POR_lf_rep r)"
    unfolding POR_lf_rep_def
    using adm_POR_base_lf_rep[of r] adm_fn[of r] by simp
qed

lemma mono_POR_lf:
  "mono POR_lf"
  apply (rule monoI)
  apply simp
  unfolding POR_lf_rep_def
  using mono_fn_lf_rep mono_POR_base_lf_rep
  apply (blast dest: monoD)
  done

(*>*)
text

  it yields an admissible relation and is monotonic.

  need to show the functor respects the minimal invariant.

 


lemma min_inv_POR_lf:
  assumes "eRSV e R' S'"
  shows "eRSV (ValD_copy_rece) (dual (POR_lf (dual S', undual R'))) (POR_lf (R', S'))"
(*<*)
  apply clarsimp
  apply (simp add: POR_lf_rep_def)
  apply (elim disjE)
   apply (rule disjI1)
   apply (auto simp: POR_base_lf_rep_def eta_cfun cfcomp1 cfun_eq_iff)[1]
  apply (rule disjI2)
  using assms
  apply (clarsimp simp: fn_lf_rep_def eta_cfun)
  apply (simp add: cfcomp1 cfun_map_def)
  apply (rule_tac x="λi. Λ xa. e(fs i(exa))" in exI)
  apply force
  done

interpretation POR: DomSolV POR_lf ValD_copy_rec
  apply standard
    apply (rule mono_POR_lf)
   apply (rule ValD_copy_ID)
  apply (erule min_inv_POR_lf)
  done

lemma PORI [intro, simp]:
  "(λi. ValTT) unlr POR.delta"
  "(λi. ValFF) unlr POR.delta"
  "(λi. ValNn) unlr POR.delta"
  "f One = ==> f unlr POR.delta"
  "f Two = ==> f unlr POR.delta"
  "[ xs. xs unlr POR.delta ==> (λj. (fs j)(xs j)) unlr POR.delta ] ==> (λi. ValF(fs i)) unlr POR.delta"
  by (subst POR.delta_sol, simp, subst POR_lf_rep_def,
      fastforce simp: POR_base_lf_rep_def fn_lf_rep_def eta_cfun cfcomp1)+

lemma PORE:
  "[ a unlr POR.delta;
     (a = (λi. ValTT) ==> P);
     (a = (λi. ValFF) ==> P);
     (n. a = (λi. ValNn) ==> P);
     (a One = ==> P);
     (a Two = ==> P);
     (fs. [ a = (λi. ValF(fs i)); xs. xs unlr POR.delta ==> (λj. (fs j)(xs j)) unlr POR.delta ] ==> P)
   ] ==> P"
  apply (subst (asm) POR.delta_sol)
  apply simp
  apply (subst (asm) POR_lf_rep_def)
  apply (fastforce simp: POR_base_lf_rep_def fn_lf_rep_def eta_cfun)
  done

lemma POR_strict_appI:
  assumes "xs unlr POR.delta"
  assumes "xs. xs unlr POR.delta ==> (λj. fs j(xs j)) unlr POR.delta"
  shows "(λj. strictify(fs j)(xs j)) unlr POR.delta"
using assms by - (erule PORE; simp)

lemma logical_relation_POR:
  "logical_relation (unlr POR.delta)"
  apply (rule logical_relationI)

  (* Strict application *)
  prefer 2
  apply (cut_tac fs="λi. appF(fs i)" and xs=xs in POR_strict_appI)
   apply simp_all
  apply (auto elim: PORE)[1]

  (* FIXME fixD *)
  prefer 2
  apply (erule PORE)
  apply (simp_all add: fixD_def)
  apply (subst fix_argument_promote_fun)
  apply (rule_tac F="Λ f. (λx. fs x(f x))" in fix_ind)
  apply (simp_all split: nat.split add: cont_fun)

  apply (auto elim: PORE simp: cond_def isZero_def pred_def succ_def eta_cfun split: nat.split)
  done

lemma PCF_consts_rel_POR:
  "PCF_consts_rel (unlr POR.delta)"
  by (rule PCF_consts_relI) simp_all

(*>*)
text

  can show that the solution satisfies the expectations of the
  theorem @{thm [source] "lr_fundamental"}.

 


lemma PCF_lr_POR_delta: "PCF_lr (unlr POR.delta)"
(*<*)
  using logical_relation_POR PCF_consts_rel_POR by fastforce
(*>*)
text

  is the truth-table for POR rendered as a vector: we seek a
  that simultaneously maps the two argument vectors to the
 .

 


definition POR_arg1_rel where
  "POR_arg1_rel λi. case i of One ==> ValTT | Two ==> | Three ==> ValFF"

definition POR_arg2_rel where
  "POR_arg2_rel λi. case i of One ==> | Two ==> ValTT | Three ==> ValFF"

definition POR_result_rel where
  "POR_result_rel λi. case i of One ==> ValTT | Two ==> ValTT | Three ==> ValFF"

lemma lr_POR_arg1_rel: "POR_arg1_rel unlr POR.delta"
  unfolding POR_arg1_rel_def by auto

lemma lr_POR_arg2_rel: "POR_arg2_rel unlr POR.delta"
  unfolding POR_arg2_rel_def by auto

lemma lr_POR_result_rel: "POR_result_rel unlr POR.delta"
(*<*)
  unfolding POR_result_rel_def
  apply clarify
  apply (erule PORE)
  apply (auto iff: fun_eq_iff split: Three.splits)
  done

(*>*)
text

 -or satisfies these tests:

 


theorem POR_sat:
  "appFLv (ValF(Λ x. ValF(Λ y. x por y))) [POR_arg1_rel, POR_arg2_rel] = POR_result_rel"
  unfolding POR_arg1_rel_def POR_arg2_rel_def POR_result_rel_def
  by (simp add: fun_eq_iff split: Three.splits)

text

 .. but is not PCF-definable:

 


theorem POR_is_not_definable:
  shows "¬(f. definable f appFLv f [POR_arg1_rel, POR_arg2_rel] = POR_result_rel)"
  apply (rule not_definable[where R="unlr POR.delta"])
    using lr_POR_arg1_rel lr_POR_arg2_rel lr_POR_result_rel PCF_lr_POR_delta
    apply simp_all
  done


subsectionPlotkin's existential quantifier

text

  can also show that the existential quantifier of
 🍋\S5 in "Plotkin77" is not PCF-definable using logical relations.

  definition is quite loose; if the argument function @{term "f"}
  any value to @{term "ValTT"} then @{term "plotkin_exists"} yields
 {term "ValTT"}. It may be more plausible to test @{term "f"} on
  only.

 


definition plotkin_exists :: "ValD ==> ValD" where
  "plotkin_exists f
     if (appFf = ValFF)
       then ValFF
       else if (n. appFfn = ValTT) then ValTT else "
(*<*)

lemma plotkin_exists_simps [simp]:
  "plotkin_exists = "
  "plotkin_exists (ValF) = "
  "plotkin_exists (ValF(Λ _. ValFF)) = ValFF"
  unfolding plotkin_exists_def by simp_all

lemma plotkin_exists_tt [simp]:
  "appFf(ValNn) = ValTT ==> plotkin_exists f = ValTT"
  unfolding plotkin_exists_def
  using monofun_cfun_arg[where f="appFf" and x=""]
  by auto

lemma monofun_pe:
  "monofun plotkin_exists"
proof(rule monofunI)
  fix f g assume fg: "(f::ValD) g"
  let ?goal = "plotkin_exists f plotkin_exists g"
  {
    assume fbot: "appFf = ValFF"
    with fg have "appFg = ValFF"
      using monofun_cfun[where f="appFf" and g="appFg" and x=""]
      by (simp add: monofun_cfun_arg)
    with fbot have ?goal by (simp add: plotkin_exists_def)
  }
  moreover
  {
    assume efn: "n. appFfn = ValTT"
    then obtain n where fn: "appFfn = ValTT" by blast
    then have fbot: "appFf ValFF"
      using monofun_cfun_arg[where f="appFf" and x="" and y="n"by fastforce
    from fg have "appFfn appFgn"
      using monofun_cfun_arg[OF fg, where f=appF]
      by (simp only: cfun_below_iff)
    with fn have gn: "appFgn = ValTT"
      using ValD.nchotomy[where y="appFg"by simp
    then have gbot: "appFg ValFF"
      using monofun_cfun_arg[where f="appFg" and x="" and y="n"by fastforce
    from fn gn fbot gbot have ?goal apply (unfold plotkin_exists_def) by fastforce
  }
  moreover
  {
    assume fbot: "appFf ValFF" and efn: "¬(n. appFfn = ValTT)"
    then have ?goal by (simp add: plotkin_exists_def)
  }
  ultimately show ?goal unfolding plotkin_exists_def by blast
qed

(*>*)
text

  can show this function is continuous.

 


lemma cont_pe [cont2cont, simp]: "cont plotkin_exists"
(*<*)
proof (rule contI2[OF monofun_pe])
  fix Y assume Y: "chain (Y :: nat ==> ValD)"
  let ?goal = "plotkin_exists ( i. Y i) ( i. plotkin_exists (Y i))"
  have peY: "chain (λi. plotkin_exists (Y i))"
    by (rule chainI, simp add: monofunE[OF monofun_pe] chainE[OF Y])
  {
    assume "i. appF(Y i) = ValFF"
    then obtain i where Yi: "appF(Y i) = ValFF" by blast
    have "Y i ( i. Y i)"
      using is_ub_thelub[OF Y, where x=i] by simp
    then have "appF(Y i) appF( i. Y i)" by (fastforce intro: monofun_cfun)
    with Yi have "ValFF appF( i. Y i)" by simp
    then have "appF( i. Y i) = ValFF" using ValD.nchotomy[where y="appF( i. Y i)"by simp
    moreover
    from Yi have "plotkin_exists (Y i) = ValFF" by (simp add: plotkin_exists_def)
    then have "ValFF ( i. plotkin_exists (Y i))" using is_ub_thelub[OF peY, where x=i] by simp
    then have "ValFF = ( i. plotkin_exists (Y i))" using ValD.nchotomy[where y=" i. plotkin_exists (Y i)"by simp
    ultimately have ?goal by (simp add: plotkin_exists_def)
  }
  moreover
  {
    assume "i j. appF(Y i)j = ValTT"
    then obtain i j where Yij: "appF(Y i)j = ValTT" by blast
    from Yij have Yib: "appF(Y i) ValFF"
      using monofun_cfun_arg[where f="appF(Y i)" and x="" and y=j] by clarsimp
    moreover
    from Yij have "appF(Y i)j appF( i. Y i)j"
      using is_ub_thelub[OF Y, where x=i] by (fastforce intro: monofun_cfun)
    with Yij have Yjlub: "appF( i. Y i)j = ValTT"
      using ValD.nchotomy[where y="appF( i. Y i)j"by simp
    moreover
    from Yjlub have "appF( i. Y i) ValFF"
      using monofun_cfun_arg[where f="appF( i. Y i)" and x="" and y=j] by auto
    moreover
    from Yib Yij have "plotkin_exists (Y i) = ValTT" by (auto simp add: plotkin_exists_def)
    then have "ValTT ( i. plotkin_exists (Y i))" using is_ub_thelub[OF peY, where x=i] by simp
    then have "ValTT = ( i. plotkin_exists (Y i))" using ValD.nchotomy[where y=" i. plotkin_exists (Y i)"by simp
    ultimately have ?goal by (simp add: plotkin_exists_def)
  }
  moreover
  {
    assume nFF: "¬(i. appF(Y i) = ValFF)" and nTT: "¬(i j. appF(Y i)j = ValTT)"
    with Y have ?goal
      unfolding plotkin_exists_def
      using compact_below_lub_iff[OF ValD.compacts(2)]
            compact_below_lub_iff[OF ValD.compacts(3)]
      by (simp add: contlub_cfun_arg contlub_cfun_fun)
  }
  ultimately show ?goal by blast
qed

lemma cont_pe2[cont2cont, simp]: "cont f ==> cont (λx. plotkin_exists (f x))"
  by (rule cont_apply) simp_all

(*>*)
text

  we construct argument and result test vectors such that @{term
 plotkin_exists"} satisfies these tests but no PCF-definable term
 .

 


definition PE_arg_rel where
  "PE_arg_rel λi. ValF(case i of
        0 ==> (Λ _. ValFF)
      | Suc n ==> (Λ (ValNx). if x = Suc n then ValTT else ))"

definition PE_result_rel where
  "PE_result_rel λi. case i of 0 ==> ValFF | Suc n ==> ValTT"

text

  that unlike the POR case the argument relation does not
  PE: we don't treat functions that return @{term "ValTT"}s
  @{term "ValFF"}s.

  Plotkin existential satisfies these tests:

 


theorem pe_sat:
  "appFLv (ValF(Λ x. plotkin_exists x)) [PE_arg_rel] = PE_result_rel"
  unfolding PE_arg_rel_def PE_result_rel_def
  by (clarsimp simp: fun_eq_iff split: nat.splits)

text

  for POR, the difference between the two vectors is that the
  can diverge but not the result.

 


definition PE_base_lf_rep :: "(nat ==> ValD) lf_rep" where
  "PE_base_lf_rep λ(mR, pR).
     { }
    { (λi. ValTT) } { (λi. ValFF) } ― x = y = z for bools
    (n. { (λi. ValNn) }) ― x = y = z for numerals
    { f . f 1 = f 2 = } ― Vectors that diverge on one or two."
(*<*)

lemma adm_PE_base_lf_rep:
  "adm (λx. x  PE_base_lf_rep r)"
unfolding PE_base_lf_rep_def
using adm_below_monic_exists[OF _ below_monic_fun_K[where f=ValN], where P="λ_. True"]
by (auto intro!: adm_disj simp: cont_fun)

lemma mono_PE_base_lf_rep:
  "mono PE_base_lf_rep"
unfolding PE_base_lf_rep_def
by (blast intro!: monoI)

(*>*)
text

Again we close this under the function space, and show that it is
admissible, monotonic and respects the minimal invariant.

\<close>

definition PE_lf_rep :: " nat ==> ValD) lf_rep" where
 "PE_lf_rep R PE_base_lf_rep R fn_lf_rep R"

  "PE_lf λr. mklr (PE_lf_rep r)"
(*<*)

lemma admS_PE_lf [intro, simp]:
  "PE_lf_rep r admS"
proof
  show " PE_lf_rep r"
    unfolding PE_lf_rep_def PE_base_lf_rep_def
    by simp
next
  show "adm (λx. x PE_lf_rep r)"
    unfolding PE_lf_rep_def
    using adm_PE_base_lf_rep[of r] adm_fn[of r] by simp
qed

lemma mono_PE_lf:
  "mono PE_lf"
  apply (rule monoI)
  apply simp
  unfolding PE_lf_rep_def
  using mono_fn_lf_rep mono_PE_base_lf_rep
  apply (blast dest: monoD)
  done

lemma min_inv_PE_lf:
  assumes "eRSV e R' S'"
  shows "eRSV (ValD_copy_rece) (dual (PE_lf (dual S', undual R'))) (PE_lf (R', S'))"
  apply clarsimp
  apply (simp add: PE_lf_rep_def)
  apply (elim disjE)
   apply (rule disjI1)
   apply (auto simp: PE_base_lf_rep_def eta_cfun cfcomp1 cfun_eq_iff)[1]
  apply (rule disjI2)
  using assms
  apply (clarsimp simp: fn_lf_rep_def eta_cfun)
  apply (simp add: cfcomp1 cfun_map_def)
  apply (rule_tac x="λx. Λ xa. e(fs x(exa))" in exI)
  apply force
  done

interpretation PE: DomSolV PE_lf ValD_copy_rec
  apply standard
    apply (rule mono_PE_lf)
   apply (rule ValD_copy_ID)
  apply (erule min_inv_PE_lf)
  done

lemma PEI [intro, simp]:
  " unlr PE.delta"
  "(λi. ValTT) unlr PE.delta"
  "(λi. ValFF) unlr PE.delta"
  "(λi. ValNn) unlr PE.delta"
  "f 1 = ==> f unlr PE.delta"
  "f 2 = ==> f unlr PE.delta"
  "[ xs. xs unlr PE.delta ==> (λj. (fs j)(xs j)) unlr PE.delta ] ==> (λi. ValF(fs i)) unlr PE.delta"
  by (subst PE.delta_sol, simp, subst PE_lf_rep_def,
      fastforce simp: PE_base_lf_rep_def fn_lf_rep_def eta_cfun cfcomp1)+

lemma PE_fun_constI:
  "[ xs. xs unlr PE.delta ==> (λj. f(xs j)) unlr PE.delta ] ==> (λi. ValFf) unlr PE.delta"
  using PEI(7)[where fs="λ_. f"by simp

lemma PEE:
  "[ a unlr PE.delta;
     (a = ==> P);
     (a = (λi. ValTT) ==> P);
     (a = (λi. ValFF) ==> P);
     (n. a = (λi. ValNn) ==> P);
     (a 1 = ==> P);
     (a 2 = ==> P);
     (fs. [ a = (λj. ValF(fs j)); xs. xs unlr PE.delta ==> (λj. (fs j)(xs j)) unlr PE.delta ] ==> P)
   ] ==> P"
  apply (subst (asm) PE.delta_sol)
  apply simp
  apply (subst (asm) PE_lf_rep_def)
  apply (fastforce simp: PE_base_lf_rep_def fn_lf_rep_def eta_cfun)
  done

lemma PEE_strict_appI:
  assumes "xs unlr PE.delta"
  assumes "xs. xs unlr PE.delta ==> (λj. fs j(xs j)) unlr PE.delta"
  shows "(λj. strictify(fs j)(xs j)) unlr PE.delta"
  using assms
  apply -
  apply (erule PEE)
  apply simp_all
  done

lemma logical_relation_PE:
  "logical_relation (unlr PE.delta)"
apply (rule logical_relationI)

  (* Strict application *)
  prefer 2
  apply (cut_tac fs="λi. appF(fs i)" and xs=xs in PEE_strict_appI)
   apply simp_all
  apply (auto elim: PEE)[1]

  (* FIXME fixD *)
  prefer 2
  apply (erule PEE)
  apply (simp_all add: fixD_def)
  apply (subst fix_argument_promote_fun)
  apply (rule_tac F="Λ f. (λx. fs x(f x))" in fix_ind)
  apply (simp_all split: nat.split add: cont_fun)

  apply (auto elim: PEE simp: cond_def isZero_def pred_def succ_def eta_cfun split: nat.split)
  done

lemma PCF_consts_rel_PE:
  "PCF_consts_rel (unlr PE.delta)"
  by (rule PCF_consts_relI) simp_all
(*>*)
text

  solution satisfies the expectations of the fundamental theorem:

 


lemma PCF_lr_PE_delta: "PCF_lr (unlr PE.delta)"
(*<*)
  using logical_relation_PE PCF_consts_rel_PE by fastforce
(*>*)

lemma lr_PE_arg_rel: "PE_arg_rel unlr PE.delta"
(*<*)
  unfolding PE_arg_rel_def
  apply (rule PEI(7))
  apply (erule PEE)
   apply simp_all
  apply (case_tac n)
   apply simp
  apply (case_tac nat)
   apply simp_all
  done
(*>*)

lemma lr_PE_result_rel: "PE_result_rel unlr PE.delta"
(*<*)
unfolding PE_result_rel_def
apply clarify
apply (erule PEE)
apply (auto iff: fun_eq_iff split: nat.splits)
done
(*>*)

theorem PE_is_not_definable: "¬(f. definable f appFLv f [PE_arg_rel] = PE_result_rel)"
(*<*)
apply (rule not_definable[where R="unlr PE.delta"])
  using lr_PE_arg_rel lr_PE_result_rel PCF_lr_PE_delta
  apply simp_all
done
(*>*)

subsectionConcluding remarks

text

  techniques could be used to show that Haskell's seq
  is not PCF-definable. (It is definable for each base
 `type'' separately, and requires some care on function values.) If we
  an (unlifted) product type then it should be provable that
  evaluation is required to support seq on these
  (given seq on all other objects). (See
 🍋\S5.4 in "DBLP:conf/hopl/HudakHJW07" and sundry posts to the
  by Lennart Augustsson.) This may be difficult to do plausibly
  adding a type system.

 


(*<*)

end
(*>*)

Messung V0.5 in Prozent
C=73 H=93 G=83

¤ Dauer der Verarbeitung: 0.21 Sekunden  (vorverarbeitet am  2026-06-10) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.