Coq: Resolve an expression to multiple instances - class

In a scenario like this, I want a single expression to resolve to multiple instances:
Inductive SR: Prop := Sen | Inf.
Parameter CA S: Prop.
Parameter X: SR -> CA -> Prop -> Prop.
Parameter X': SR -> CA -> Prop -> Set.
Parameter XP: SR -> CA -> Prop -> Type.
Definition iX' (t:bool): SR -> CA -> Prop -> Type := if t then X' else XP.
Context `{b:bool}`{c:bool}`{d:bool}`{s:SR}`{t:SR}`{u:SR}`{k:CA}`{l:CA}`{m:CA}`{o:Prop}`{p:Prop}`{q:Prop}.
Parameter foo: iX' b s k o.
Parameter foo'': iX' d u m q.
Parameter ss: S.
Class CON (f:bool) := an: if f then iX' b s k o -> iX' c t l p -> iX' d u m q else S -> S -> S.
Instance coni: CON true := fun (_:iX' b s k o) (_:iX' c t l p) => foo''.
Instance conj: CON false := fun (_:S) (_:S) => ss.
Check (_: CON false) ss.
Check (_: CON true) foo.
Check (_: CON _) ss.
Check (_: CON _) foo. (*Error: The term "foo" has type "iX' b s k o" while it is expected to have type "S".*)
Is there a way to make the instance resolution work w/ both (_: CON _) foo and (_: CON _) ss? If not, try to succeed in a scenario where the class and/or instances are different, while ... in Check ... ss and Check ... foo is identical, and resolves to functions fun (_:S) (_:S) => ss and fun (_:iX' b s k o) (_:iX' c t l p) => foo'', resp.

Is there any reason to restrict yourself to instances here? If you're already doing this much hackery, you might as well go a bit further and use tactics in terms in notations.
Ltac mkcon arg :=
match constr:(Set) with
| _ => exact ((_ : CON false) arg)
| _ => exact ((_ : CON true) arg)
end.
Notation CON_ arg := ltac:(mkcon arg) (only parsing).
Check (_: CON false) ss.
Check (_: CON true) foo.
Check CON_ ss.
Check CON_ foo.

Related

Purescript: Could not match type

In the REPL this works:
> mm n = (\n -> n * 2) <$> n
> mm (2:3:Nil)
(4 : 6 : Nil)
in a file this compiles and I can run it:
squareOf ls =
map (\n -> n * n) ls
however when I add a type definition to that function
squareOf :: List Int -> Int
squareOf ls =
map (\n -> n * n) ls
I get an error:
Could not match type
List Int
with type
Int
while checking that type t0 t1
is at least as general as type Int
while checking that expression (map (\n ->
(...) n
)
)
ls
has type Int
in value declaration squareOf
where t0 is an unknown type
t1 is an unknown type
I tried changing the signature to a type alias of the list, and also I tried a forall definition with no luck.
If I inspect the definition created when I don't put signatures in my function I get:
forall t2 t3. Functor t2 => Semiring t3 => t2 t3 -> t2 t3
Can anyone explain why my signature is incorrect and also why am I getting this signature for the function?
Cheers
Edit: Thanks for the comments, updating the fn definition so it returns a List Int as well, and , of course it solves the problem
Assuming you're repl function is the behaviour you're after, you've missed out the map operator (<$>) in your later definitions.
Your repl function (with variables renamed for clarity) has the type:
mm :: forall f. Functor f => f Int -> f Int
mm ns = (\n -> n * 2) <$> ns
Which is to say: mm maps "times two" to something that is mappable" (i.e. a Functor)
Aside: you could be more concise/clear in your definition here:
mm :: forall f. Functor f => f Int -> f Int
mm = map (_*2)
This is similar to your squareOf definition, only now you're squaring so your use of (*) is more general:
squareOf :: forall f. Functor f => Semiring n => f n -> f n
squareOf = map \n -> n * n
Because (*) is a member of the Semiring typeclass.
But the signature you gave it suggests you're after some kind of fold? Let me know what output you expect from your squareOf function and I'll update the answer accordingly.
Here is map:
class Functor f where
map :: forall a b. (a -> b) -> f a -> f b
Narrowing to List Int and Int -> Int, the compiler infers
map :: (Int -> Int) -> List Int -> List Int
So, in squareOf, the expression reduces to a list of integers, not an integer. That is why the compiler complains.

generalize purescript function using MonadAff

I have a question about generalizing. Starting with this function:
test0 :: String -> String
test0 s = s
we can generalize it in its argument:
test1 :: forall a. Show a => a -> String
test1 s = show s
or in its functional result:
test12 :: forall a. Show a => String -> a
test12 s = s
Now consider the following function:
test2 :: forall e. Aff e Int
test2 s = pure 0
I would like to generalize it in its functional result:
test3 :: forall e m. MonadAff e m => m e Int
test3 s = pure 0
However, I now get an error:
Could not match kind type with kind # Control.Monad.Eff.Effect while checking the kind of MonadAff e m => m e Int in value declaration test3.
I cannot understand why. Moreover, I've found an example of similar such generalizing in Hyper.Node.Server, for example in this type:
write :: forall m e. MonadAff e m => Buffer -> NodeResponse m e
The constraint MonadAff e m asserts that the monad m somehow wraps Aff e somewhere inside. But it doesn't assert that monad m itself must have a type argument e. That would be awfully restrictive, wouldn't it?
Therefore, when constructing your return type, don't apply m to e:
test3 :: forall e m. MonadAff e m => m Int
test3 = pure 0
The example you found is quite different. Here, the function is not returning a value in m, like in your test3, but rather a value NodeResponse, which is a wrapper around a function that returns m Unit.

Coq: Defining a type class instance

In the development below, I get a strange error when trying to define an instance of a single-method typeclass:
Universe ARG. Definition ARG := Type#{ARG}.
Universe ARG0. Definition ARG0 := Type#{ARG0}.
Universe ARG1. Definition ARG1 := Type#{ARG1}.
Universe ARG2. Definition ARG2 := Type#{ARG2}.
Constraint ARG<ARG0, ARG0<ARG1, ARG1<ARG2.
Inductive SR: ARG := Phy | Sen | Inf | Lim.
Parameter CA: Prop.
Parameter X: SR -> CA -> ARG -> ARG.
Parameter X': SR -> CA -> ARG -> ARG0.
Parameter XP: SR -> CA -> ARG -> ARG1.
Parameter XP': SR -> CA -> ARG -> ARG2.
Inductive tri:Set := one | two | three.
Definition iX' (t:tri): SR -> CA -> ARG -> ARG2 := match t with one => X' | two => XP | three => XP' end.
Parameter gk:> forall (b:SR)(d:CA)(c:ARG), X' b d c -> iX' one b d c.
Parameter gl:> forall (b:SR)(d:CA)(c:ARG), XP b d c -> iX' two b d c.
Parameter gm:> forall (b:SR)(d:CA)(c:ARG), XP' b d c -> iX' three b d c.
Definition iX'bsko {b:tri}{s:SR}{k:CA}{o:ARG} := iX' b s k o.
Parameter foo: forall {b:tri}{s:SR}{k:CA}{o:ARG}, iX' b s k o.
Fail Check foo: forall {b:tri}{s:SR}{k:CA}{o:ARG}, iX' b s k o. (*Why?*)
Check foo: iX'bsko.
Class CONN := p5 (x y z:ARG): x -> y -> z.
Instance cco: CONN := fun x y iX'bsko (_:x) (_:y) => foo.
(* Error: "foo" has type "iX' ?b#{y0:=x0; y1:=y0} ?s#{y0:=x0; y1:=y0} ?k#{y0:=x0; y1:=y0} ?o#{y0:=x0; y1:=y0}"
while it is expected to have type "iX'bsko". *)
The cause of the error seems to be that foo doesn't have type iX'bsko, while 2 lines above foo: iX'bsko type checked. How do I solve this problem?
To answer your comment (*Why?*), the issue is that foo means #foo _ _ _ _. The following succeds:
Check #foo: forall {b:tri}{s:SR}{k:CA}{o:ARG}, iX' b s k o.
To answer your question, you have shot yourself in the foot by shadowing the global iX'bsko with a local opaque variable.
If you change
Instance cco: CONN := fun x y iX'bsko (_:x) (_:y) => foo.
to
Instance cco: CONN := fun x y not_really_iX'bsko' (_:x) (_:y) => foo.
you get
Error:
In environment
x : ARG
y : ARG
not_really_iX'bsko : ARG
x0 : x
y0 : y
The term "foo" has type
"iX' ?b#{y0:=x0; y1:=y0} ?s#{y0:=x0; y1:=y0} ?k#{y0:=x0; y1:=y0}
?o#{y0:=x0; y1:=y0}" while it is expected to have type
"not_really_iX'bsko".
This is not surprising. CONN is the type forall x y z : Type#{ARG}, x -> y -> z. This type has no inhabitants:
Lemma no_conn : CONN -> False.
Proof. exact (fun cco => cco True True False I I). Qed.
Perhaps you meant to make x, y, and z arguments to CONN instead, writing something like this?
Class CONN (x y z:ARG) := p5 : x -> y -> z.
Instance cco x y : CONN x y iX'bsko := fun (_:x) (_:y) => foo.
Note that this fails with a much more clear-cut error message:
The term "iX'bsko" has type "ARG2" while it is expected to have type
"ARG" (universe inconsistency).
If you instead do
Class CONN (x y z:ARG2) := p5 : x -> y -> z.
Instance cco x y : CONN x y iX'bsko := fun (_:x) (_:y) => foo.
then you get
Error: Cannot infer the implicit parameter b of iX'bsko whose type is
"tri" in environment:
x, y : ARG2

Supplying section arguments for examples

Consider this section:
Section MyMap.
Variables D R : Type.
Fixpoint mymap (f : D -> R) (l : list D) : list R :=
match l with
| nil => nil
| d :: t => f d :: mymap f t
end.
End MyMap.
Here I've used Variables to declare my domain and range types. As a sanity check on the definition of my function, I would like to include an Example:
Example example_map_S : mymap S [0; 1; 2] = [1; 2; 3].
Proof.
simpl; trivial.
Qed.
However it seems I can't do so within my section. Instead I get:
Error: The term "S" has type "nat -> nat" while it is expected to have type "D -> R".
That's not too surprising, so let's try it another way:
Example example_map_S : #mymap nat nat S [0; 1; 2] = [1; 2; 3].
Proof.
simpl; trivial.
Qed.
Which produces:
Error: The term "nat" has type "Set" while it is expected to have type "D -> R".
I suppose that's fair, section-ized Variables aren't the same thing as implicit arguments. But it still leaves the question!
How can I supply concrete Variables to a term before closing the section, in order to create useful Examples?
Section MyMap.
...
If we check the type of mymap inside the section, we get
Check mymap.
(* mymap : (D -> R) -> list D -> list R *)
Of course, we can't unify D and R with nat, since D and R are some locally postulated types.
However, we can sort of simulate your example in this generalized setting, showing the expected property of the mymap function:
Example example_nil (f : D -> R) :
mymap f [] = [] := eq_refl.
Example example_3elems (f : D -> R) (d0 d1 d2 : D) :
mymap f [d0; d1; d2] = [f d0; f d1; f d2] := eq_refl.
End MyMap.

Mutualy recursive function and termination checker in Coq

EDIT
Require Import Bool List ZArith.
Variable A: Type.
Inductive error :=
| Todo.
Inductive result (A : Type) : Type :=
Ok : A -> result A | Ko : error -> result A.
Variable bool_of_result : result A -> bool.
Variable rules : Type.
Variable boolean : Type.
Variable positiveInteger : Type.
Variable OK: result unit.
Definition dps := rules.
Inductive dpProof :=
| DpProof_depGraphProc : list
(dps * boolean * option (list positiveInteger) * option dpProof) -> dpProof.
Fixpoint dpProof' (R D: rules) (p: dpProof) {struct p}:=
match p with
| DpProof_depGraphProc cs => dpGraphProc R D cs
end
with dpGraphProc (R D: rules ) cs {struct cs} :=
match cs with
| nil => Ko unit Todo
| (_, _, _, op) :: cs' =>
match op with
| None => Ko unit Todo
| Some p2 => dpProof' R D p2
end
end.
I got an error message saying that:
Recursive call to dpProof has principal argument equal to
"p2" instead of "cs'".
Recursive definition is:
"fun (R D : rules)
(cs : list
(dps * boolean * option (list positiveInteger) *
option dpProof)) =>
match cs with
| nil => Ko unit Todo
| (_, _, _, Some p2) :: _ => dpProof' R D p2
| (_, _, _, None) :: _ => OK
end".
If I do not use the mutual recursive and use the nested fixpoint, it will combine and pass the checker of termination. Here is the code that successfully combined.
Fixpoint dpProof' (R D: rules) (p: dpProof) {struct p}:=
match p with
| DpProof_depGraphProc cs =>
match cs with
| nil => Ko _ Todo
| (_, _, _, op) :: cs' =>
match op with
| None => Ko unit Todo
| Some p2 => dpProof' R D p2
end
end end.
I would like to understand deeper about the reason why it cannot pass the termination checker? Is it because they cannot guess the argument descreasing? Is there any way that I can use the mutually recursive to express my function dpGraphProc?
Also How can I write the function dpGraphProc that check in the whole list? Here I do not know how to use the argument cs'.
Mutual recursion is to be used either with a single inductive data-type or with different inductive data-types that have been defined together in a single inductive definition. In your case, you are using polymorphic data-types prod (the type of pairs), list, and option which were already defined before dpProof.
The nested fixpoint approach does not have the restriction.