0

My attempt to create a custom linear order for a custom data type failed, Below is my code:

theory Scratch
imports Main 
begin

  datatype st  = Str "string"

  fun solf_str_int:: "string ⇒ int" where
    "solf_str_int str = (if (size str) > 0
                       then int(nat_of_char (hd str) + 1) + 100 *     (solf_str_int (tl str))
                       else 0)"

  fun soflord:: "st ⇒ st ⇒ bool" where
    "soflord s1 s2 = (case s1 of Str ss1 ⇒ (case s2 of Str ss2 ⇒ 
                        (solf_str_int ss1) ≤ (solf_str_int ss2)))"

instantiation st :: linorder
begin
  definition nleq: "less_eq n1 n2 == soflord n1 n2"  
  definition neq: "eq n1 n2 == (n1 ≤ n2) ∧ (n2 ≤ n1)"
  definition nle:  "less n1 n2 == (n1 ≤ n2) ∧ (¬(n1 = n2))" (* ++ *)

  instance proof
    fix n1 n2 x y :: st
    show "n1 ≤ n1" by (simp add:nleq split:st.split)
    show "(n1 ≤ n2) ∨ (n2 ≤ n1)" by (simp add:nleq split:st.split)     (*why is 'by ()' highlited?*)
    (*this fail if I comment line ++ out*)
    show "(x < y) = (x ≤ y ∧ (¬ (y ≤ x)))" by (simp add:nleq neq split:node.split)

  qed
end
end

The definition marked with (* ++ *) is not right and if delete it the last show give problems.

How do I correct the prove? Why is the second last show partially highlighted?

Johan
  • 575
  • 5
  • 21

1 Answers1

2

When you define the operations of a type class (less_eq and less in the case of linorder), the name of the overloaded operation can only be used if the inferred type of the operation matches exactly the overloaded instance that is being defined. In particular, the type is not specialised if it turns out to be too general.

The definition for less_eq works because soflord restricts the types of n1 and n2 to st, so less_eq is used with type st => st => bool, which is precisely what is needed here. For less, type inference computes the most general type 'b :: ord => 'b => bool. As this is not of the expected type st => st => bool, Isabelle does not recognize the definition as a definition of an overloaded operation and consequently complains that you want to redefine an existing operation in its full generality. If you restrict the types as necessary, then the definition works as expected.

definition nle:  "less n1 (n2 :: st) == (n1 ≤ n2) ∧ (¬(n1 = n2))"

However, your definitions do not define a linear order on st. The problem is that antisymmetry is violated. For example, the two strings Str ''d'' and Str [Char Nibble0 Nibble0, Char Nibble0 Nibble0] (i.e., the string consisting of two characters at codepoint 0) are "equivalent" in your order, although they are different values. You attempt to define equality on st, too, but in higher-order logic, equality cannot be defined. It is determined by the way you constructed your type. If you really want to identify strings that are equivalent according to your order, you have to construct a quotient first, e.g., using the quotient package.

The purple highlighting of by(simp ...) indicates that the proof method simp is still running. In your case, it will not terminate, because simp will keep unfolding the defining equation for solf_str_int: its right-hand side contains an instance of the left-hand side. I recommend that you define your functions by pattern-matching on the left-hand side of =. Then, the equations are only used when they can consume a pattern. Thus, you have to trigger case distinctions yourself (e.g. using cases), but you also get more control over the automated tactics.

Andreas Lochbihler
  • 4,998
  • 12
  • 10