How to define a partial function in Isabelle?

给你一囗甜甜゛ 提交于 2019-12-02 00:55:14

问题


I tried to define a partial function with the partial_function keyword. It did not work. Here is the one that expresses the intuition best:

partial_function (tailrec) oddity :: "nat => nat"
where
  "oddity Zero = Zero "
| "oddity (Succ (Succ n)) = n"

and then I tried the following:

partial_function (tailrec) oddity :: "nat => nat"
where
  "oddity arg = ( case arg of (Succ (Succ n)) => n
                          | Zero => Zero
                )"

partial_function (tailrec) oddity :: "nat => nat"
where
  "oddity (Succ(Succ n)) = n
   | oddity Zero = Zero"

partial_function (tailrec) oddity :: "nat => nat"
where
  "oddity n =
   (if n = Zero then Zero
    else if (n >= 2)
      then do { m ← oddity (n-2); m })"

None of them worked. I guess my attempts have conceptual and syntactic problems, what are these?


回答1:


There are two problems with your definitions:

  1. partial_function does not support pattern-matching on the left hand side. This must be emulated with case expressions on the right.

  2. The constructors for type nat are Suc and 0, not Succ and Zero. This is why your case expressions generate the error that Succ and Zero are not datatype constructors, and why parital_function complains that Zero is an extra variable on the right hand side.

In summary, the following works:

partial_function (tailrec) oddity :: "nat => nat"
where "oddity arg = (case arg of (Suc (Suc n)) => n | 0 => 0 )"

You can recover simplification rules with pattern-matching by using the simp_of_case conversion from ~~/src/HOL/Library/Simps_Case_Conv:

simps_of_case oddity_simps[simp]: oddity.simps

thm oddity_simps



回答2:


Some comments concerning your last example:

  1. There is no if-then without else in Isabelle/HOL. Thus a syntax error. To fix this you would have to either provide an else-branch for your last if, or rewrite the definition. E.g.

    partial_function (tailrec) oddity :: "nat ⇒ nat"
    where
      "oddity n = (
        if n = 0 then 0
        else if n ≥ 2 then do { m ← oddity (n - 2); m }
        else undefined)"   
    
  2. At this point there will be an error about "unresolved adhoc overloading". Remember that do-notation is just syntactic sugar. Lets try to see what is actually happening by just looking at the do-block with

    term "do { m ← oddity (n - 2); m }"
    

    Since there is still the unresolved overloading lets fix the type of m to 'a list and also deactivate "pretty printing" for adhoc overloading as follows

    declare [[show_variants]]
    term "do { m ← oddity (n - 2); (m :: 'a list) }"
    

    The result is

    "List.bind (oddity (n - 2)) (λm. m)"
    

    So you see that instead of the semicolon ; you typed, a constant bind is inserted (the exact constant depends on the type). There is no bind registered for type nat, hence the above error. While you could define some kind of "identity monad" this rather shows that do-notation does not make much sense here. How about the following definition instead?

    partial_function (tailrec) oddity :: "nat ⇒ nat"
    where
      "oddity n = (
        if n = 0 then 0
        else if n ≥ 2 then oddity (n - 2)
        else undefined)"
    

    Update: For completeness sake, lets see how we could define the above mentioned identity monad. First we need a bind operation, i.e., a constant taking an identity monad and a function returning an identity monad and combining those arguments into an identity monad. A first, and most simple idea could be

    definition "bind_id' x f = f x"
    

    which is just function application in reverse order. However, with this definition we will later get problems with monotonicity of bind_id' that will be required for (tailrec). Thus we instead use

    definition "bind_id x f = (if x = undefined then undefined else f x)"
    

    which guarantees that bind_id x f is undefined whenever x is, and thus is monotone. Then we register this new constant for adhoc overloading of the monadic bind like so

    adhoc_overloading
      Monad_Syntax.bind bind_id
    

    Now it remains to prove monotonicity of bind_id w.r.t. mono_tailrec, which is left as an exercise (just mimic what is already done for mono_option in Partial_Function). Then your definition using do-notation would be accepted.

  3. It might not be your intention that oddity 1 is undefined. But since I'm not sure about the purpose of oddity I can't be sure about that.



来源:https://stackoverflow.com/questions/25280566/how-to-define-a-partial-function-in-isabelle

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!