问题
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:
partial_functiondoes not support pattern-matching on the left hand side. This must be emulated withcaseexpressions on the right.The constructors for type
natareSucand0, notSuccandZero. This is why your case expressions generate the error thatSuccandZeroare not datatype constructors, and whyparital_functioncomplains thatZerois 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:
There is no
if-thenwithoutelsein Isabelle/HOL. Thus a syntax error. To fix this you would have to either provide anelse-branch for your lastif, 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)"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
mto'a listand also deactivate "pretty printing" for adhoc overloading as followsdeclare [[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 constantbindis inserted (the exact constant depends on the type). There is nobindregistered for typenat, 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 usedefinition "bind_id x f = (if x = undefined then undefined else f x)"which guarantees that
bind_id x fisundefinedwheneverxis, and thus is monotone. Then we register this new constant for adhoc overloading of the monadic bind like soadhoc_overloading Monad_Syntax.bind bind_idNow it remains to prove monotonicity of
bind_idw.r.t.mono_tailrec, which is left as an exercise (just mimic what is already done formono_optioninPartial_Function). Then your definition using do-notation would be accepted.It might not be your intention that
oddity 1is undefined. But since I'm not sure about the purpose ofoddityI can't be sure about that.
来源:https://stackoverflow.com/questions/25280566/how-to-define-a-partial-function-in-isabelle