(* List notations for wider connectives; the Prop connectives have a fixed    *)
(* width so as to avoid iterated destruction (we go up to width 5 for /\, and *)
(* width 4 for or). The bool connectives have arbitrary widths, but denote    *)
(* expressions that associate to the RIGHT. This is consistent with the right *)
(* associativity of list expressions and thus more convenient in most proofs. *)
Inductive and4 (P1 P2 P3 P4 : Prop) : Prop := And4 of P1 & P2 & P3 & P4.
Inductive and5 (P1 P2 P3 P4 P5 : Prop) : Prop :=
And5 of P1 & P2 & P3 & P4 & P5.
Inductive or3 (P1 P2 P3 : Prop) : Prop := Or31 of P1 | Or32 of P2 | Or33 of P3.
Inductive or4 (P1 P2 P3 P4 : Prop) : Prop :=
Or41 of P1 | Or42 of P2 | Or43 of P3 | Or44 of P4.
Notation "[ /\ P1 & P2 ]" := (and P1 P2) (only parsing) : type_scope.
Notation "[ /\ P1 , P2 & P3 ]" := (and3 P1 P2 P3) : type_scope.
Notation "[ /\ P1 , P2 , P3 & P4 ]" := (and4 P1 P2 P3 P4) : type_scope.
Notation "[ /\ P1 , P2 , P3 , P4 & P5 ]" := (and5 P1 P2 P3 P4 P5) : type_scope.
Notation "[ \/ P1 | P2 ]" := (or P1 P2) (only parsing) : type_scope.
Notation "[ \/ P1 , P2 | P3 ]" := (or3 P1 P2 P3) : type_scope.
Notation "[ \/ P1 , P2 , P3 | P4 ]" := (or4 P1 P2 P3 P4) : type_scope.
Notation "[ && b1 & c ]" := (b1 && c) (only parsing) : bool_scope.
Notation "[ && b1 , b2 , .. , bn & c ]" := (b1 && (b2 && .. (bn && c) .. ))
: bool_scope.
Notation "[ || b1 | c ]" := (b1 || c) (only parsing) : bool_scope.
Notation "[ || b1 , b2 , .. , bn | c ]" := (b1 || (b2 || .. (bn || c) .. ))
: bool_scope.
Notation "[ ==> b1 , b2 , .. , bn => c ]" :=
(b1 ==> (b2 ==> .. (bn ==> c) .. )) : bool_scope.
Notation "[ ==> b1 => c ]" := (b1 ==> c) (only parsing) : bool_scope.
Section AllAnd.
Variables (T : Type) (P1 P2 P3 P4 P5 : T -> Prop).
Local Notation a P := (forall x, P x).

Lemma nandP : reflect (~~ b1 \/ ~~ b2) (~~ (b1 && b2)).