问题
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_function
does not support pattern-matching on the left hand side. This must be emulated withcase
expressions on the right.The constructors for type
nat
areSuc
and0
, notSucc
andZero
. This is why your case expressions generate the error thatSucc
andZero
are not datatype constructors, and whyparital_function
complains thatZero
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:
There is no
if-then
withoutelse
in 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
m
to'a list
and 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 constantbind
is inserted (the exact constant depends on the type). There is nobind
registered 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 f
isundefined
wheneverx
is, and thus is monotone. Then we register this new constant for adhoc overloading of the monadic bind like soadhoc_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 formono_option
inPartial_Function
). Then your definition using do-notation would be accepted.It might not be your intention that
oddity 1
is undefined. But since I'm not sure about the purpose ofoddity
I can't be sure about that.
来源:https://stackoverflow.com/questions/25280566/how-to-define-a-partial-function-in-isabelle