I'm (partially) reading Programs and Proofs by Ilya Sergey. Last exercise in chapter 2 (FunProg.v) is the following.
(**
---------------------------------------------------------------------
Exercise [Functions with dependently-typed result type]
---------------------------------------------------------------------
Write a function that has a dependent result type and whose result is
[true] for natural numbers of the form [4n + 1], [false] for numbers
of the form [4n + 3] and [n] for numbers of the from [2n].
Hint: Again, you might need to define a number of auxiliary
(possibly, higher-order) functions to complete this exercise.
*)
Failing at finding the solution, I read the solution in the git repository which is as follows:
Fixpoint dep_type (n : nat) : Set := match n with
| 0 => nat
| 1 => bool
| n'.+2 => dep_type n'
end.
Fixpoint dep_value_aux (n: nat): dep_type n -> dep_type n :=
match n return dep_type n -> dep_type n with
| 0 => fun x => x.+1
| 1 => fun x => ~~x
| n'.+2 => dep_value_aux n'
end.
Fixpoint dep_value (n: nat): dep_type n :=
match n with
| 0 => 0
| 1 => true
| n'.+2 => dep_value_aux n' (dep_value n')
end.
Coq refuses the definition of dep_value_aux with the following message:
In environment
dep_value_aux : forall n : nat, dep_type n -> dep_type n
n : nat
n0 : nat
n' : nat
The term "n'" has type "nat" while it is expected to have type "dep_type ?n".
I guess that it used to work with coq 8.11.2 but does not with 8.15.2 which is the version I use.
dep_type n' = dep_type n'.+2
and hence rejects the definition ?There's some implicit argument option somewhere that needs to be disabled for this definition to work.
Or you could probably replace | n'.+2 => dep_value_aux n'
by | n'.+2 => @dep_value_aux n'
Ah, so the behavior of Set Implicit Argument etc changed (assuming the settings were the same in both versions? if it did change, I guess it wouldn't be a regression...
My bad... I am very sorry but actually, the file with the exercises has Set Implicit Arguments
while the one with the solutions has not. I should have checked. I didn't think an implicit argument was the cause of this problem, now I will be more careful with this.
Pierre Rousselin has marked this topic as resolved.
Thanks for posting, as I found this quite a useful exercise for myself as I learn dependent types. Though it's not quite related to your question, I find the solution surprisingly over-complicated. It seems much easier to do it this way:
Require Import Nat.
Definition is_even (n : nat) : bool := n mod 2 =? 0.
Definition solution (n : nat) : if is_even n then nat else bool :=
if is_even n as e return (if e then nat else bool)
then n / 2
else is_even (n / 2).
Example solution_test_true : solution 9 = true. Proof. reflexivity. Qed.
Example solution_test_false : solution 7 = false. Proof. reflexivity. Qed.
Example solution_test_nat : solution 10 = 5. Proof. reflexivity. Qed.
Is there is some subtle reason to use the approach in the model solution?
I'd say not for this exercise; I think the pattern in the model solution can come up in practice and be worth learning, but isn't needed for this exercise indeed.
(and no I don't have a good example in mind; interpreters for intrinsically typed syntax move in that direction, and type-directed transformers can move much further. In all those cases, I'd probably reach for Coq-Equations first).
Last updated: Oct 13 2024 at 01:02 UTC