Reputation: 10784
I’m trying to re-implement an example from CPDT from memory. I wrote:
Inductive myType : Set := MyNat | MyBool.
Definition typeDenote (t : myType) : Set :=
match t with
| MyNat => nat
| MyBool => bool
end.
Inductive unaryOp : myType -> myType -> Set :=
| Twice : unaryOp MyNat MyNat.
Definition twice (n:nat) : nat := n + n.
Definition tunaryDenote (a b : myType) (t : unaryOp a b)
: typeDenote a -> typeDenote b :=
match t with
| Twice => twice
end.
The resulting error is:
Toplevel input, characters 125-130
> | Twice => twice
> ^^^^^
Error: In environment
a : myType
b : myType
t : unaryOp a b
The term "twice" has type "nat -> nat" while it is expected to have type
"forall H : typeDenote ?141, typeDenote ?142"
I don’t understand this error message. I would think that once the match on Twice : unaryOp MyNat MyNat
succeeds, Coq infers that a
and b
are MyNat
s, and thus typeDenote a -> typeDenote b ≡ nat -> nat
, making twice
a perfectly fine candidate for the return value. Where’d I go wrong?
Upvotes: 2
Views: 131
Reputation: 10784
I tried a newer version of Coq, and like others have said, it typechecks without issue on Coq 8.5. :)
Upvotes: 0
Reputation: 12103
Just like @AntonTrunov said, it is typechecked without any issue on my Coq 8.5pl1. However if you need to add some extra annotations for your version to accept the function, you want to have a look at this section of the manual to figure out what to do.
My guess is that you want to have a match ... in ... return ... with
to say that the return type should be refined by the information obtained by matching t at the type unaryOp a b
(indeed: a
and b
will take concrete values in the Twice
branch).
This is the definition you get using that technique:
Definition tunaryDenote (a b : myType) (t : unaryOp a b)
: typeDenote a -> typeDenote b :=
match t in unaryOp a b return typeDenote a -> typeDenote b with
| Twice => twice
end.
Upvotes: 1
Reputation: 21595
I think that the answer is that Coq's type inference is limited, and does not do the reasoning you want it to do.
Coq's type inference does not do arbitrary calculation but simple unification. It looks at twice
, understand that it is nat->nat
and concludes that it is not (syntactically) of the form typeDenote a -> TypeDenote b
.
If it was doing calculation, it was likely to be non-terminating, since its type system is very sophisticated so you can encode non-trivial computation there.
Upvotes: 0