theory i131031a__q1b_context_slower__needs_qualified_simp__numeral_print
imports Complex_Main
begin

(*Re: [isabelle] linordered_idom: context affecting time & simp, printing numerals
Answer by Andreas Lochbihler:
> 2) Inside the class context, the simp method will not use foo_f.simps, even
> though the output message shows that foo_f.simps are available as rewrite
> rules. Inside, linordered_idom_class.foo_f.simps must be added as a simp rule.
> Is there something I can do to get it to use foo_f.simps, without having to
> add the qualified name linordered_idom_class.foo_f.simps as a simp rule?

You are confused by Isabelle's type inference. Inside a type class context, the 
type variable 'a is fixed, i.e., inside linorderd_idom, foo_f.simps only works 
for instances of foo_f with type "'a foo_d". In your theorem, you try to 
instantiate 'a to int. This makes Isabelle think that you want to refer to the 
exported version of foo_f, so you have to add the exported foo_f.simps rules as 
well. 

And part of my answer:
As you talk about, the type variable 'a is special in the class context. If I try
`fun foo_f :: "'a::linordered_idom foo_d => real"`, I get the error `Sort 
constraint linordered_idom inconsistent with default type for type variable "'a"`. 
Using 'b works, and the two print statements show I get what I want. 
I could also be confused about instantiation.*)

datatype 'a foo_d = Foo_d 'a
context linordered_idom begin
fun foo_f :: "'b::linordered_idom foo_d => real" where
  "foo_f (Foo_d x) = real x"
  
theorem "foo_f (Foo_d (1::int)) = (1::real)"
print_statement foo_f.simps
print_statement linordered_idom_class.foo_f.simps
by(simp)
end

(*Andreas' answer about numerals not printing nice with "value":
value uses a different set of different equations for normalising terms, namely 
those declared as [code], whereas the simp method uses [simp]. You can, of course, 
try to change the setup of code generator, but that requires considerable effort. 

GB: From "[isabelle] Looking for rat & int powers to use with linordered_idom",
and the examples I was working on, I create a simple example to show that
`value "nat_of(1::int)"` gets simplified, but `value "foo_g(Foo(1::int))"`
doesn't, even though it's a simple use of nat_of(x).
*)

consts nat_of :: "'a => nat"

abbreviation (input) nat_of_int :: "int => nat" where 
  "nat_of_int == nat"
  
defs (overloaded)
  nat_of_int_def [simp,code_unfold]: "nat_of == nat_of_int"

datatype 'a foo_d2 = Foo_d2 'a
 
fun foo_g :: "'a foo_d2 => nat" where 
  "foo_g (Foo_d2 x) = nat_of(x)"

value "nat_of(1::int)"
  (* Output: "(Suc (0::nat))" :: "nat" *)
  (* With simp_trace, this is the first rewrite:
    [1]SIMPLIFIER INVOKED ON THE FOLLOWING TERM:
    (term_of_class.term_of (nat_of (1::int))) 
    [1]Applying instance of rewrite rule "??.unknown":
    (nat_of == nat) 
    [1]Rewriting:
    (nat_of == nat) *)

value "foo_g(Foo_d2(1::int))"
  (* Output: "(nat_of (1::int))" :: "nat" *)
  (* With simp_trace, this is the last rewrite:
    [1]Rewriting:
    (Numeral1 == (1::int)) 
    "(nat_of (1::int))" :: "nat" *)


(******************************************************************************)
end
(******************************************************************************)






