Mercurial > cpdt > repo
comparison src/Subset.v @ 73:535e1cd17d9a
maybe and sumor
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Fri, 03 Oct 2008 14:14:28 -0400 |
parents | 839d159cac5d |
children | a21447f76aad |
comparison
equal
deleted
inserted
replaced
72:839d159cac5d | 73:535e1cd17d9a |
---|---|
419 </pre># *) | 419 </pre># *) |
420 | 420 |
421 | 421 |
422 (** * Partial Subset Types *) | 422 (** * Partial Subset Types *) |
423 | 423 |
424 (** Our final implementation of dependent predecessor used a very specific argument type to ensure that execution could always complete normally. Sometimes we want to allow execution to fail, and we want a more principled way of signaling that than returning a default value, as [pred] does for [0]. One approach is to define this type family [maybe], which is a version of [sig] that allows obligation-free failure. *) | |
425 | |
424 Inductive maybe (A : Type) (P : A -> Prop) : Set := | 426 Inductive maybe (A : Type) (P : A -> Prop) : Set := |
425 | Unknown : maybe P | 427 | Unknown : maybe P |
426 | Found : forall x : A, P x -> maybe P. | 428 | Found : forall x : A, P x -> maybe P. |
427 | 429 |
430 (** We can define some new notations, analogous to those we defined for subset types. *) | |
431 | |
428 Notation "{{ x | P }}" := (maybe (fun x => P)). | 432 Notation "{{ x | P }}" := (maybe (fun x => P)). |
429 Notation "??" := (Unknown _). | 433 Notation "??" := (Unknown _). |
430 Notation "[[ x ]]" := (Found _ x _). | 434 Notation "[[ x ]]" := (Found _ x _). |
435 | |
436 (** Now our next version of [pred] is trivial to write. *) | |
437 | |
438 Definition pred_strong6 (n : nat) : {{m | n = S m}}. | |
439 refine (fun n => | |
440 match n return {{m | n = S m}} with | |
441 | O => ?? | |
442 | S n' => [[n']] | |
443 end); trivial. | |
444 Defined. | |
445 | |
446 (** Because we used [maybe], one valid implementation of the type we gave [pred_strong6] would return [??] in every case. We can strengthen the type to rule out such vacuous implementations, and the type family [sumor] from the standard library provides the easiest starting point. For type [A] and proposition [B], [A + {B}] desugars to [sumor A B], whose values are either values of [A] or proofs of [B]. *) | |
447 | |
448 Print sumor. | |
449 (** [[ | |
450 | |
451 Inductive sumor (A : Type) (B : Prop) : Type := | |
452 inleft : A -> A + {B} | inright : B -> A + {B} | |
453 For inleft: Argument A is implicit | |
454 For inright: Argument B is implicit | |
455 ]] *) | |
456 | |
457 (** We add notations for easy use of the [sumor] constructors. The second notation is specialized to [sumor]s whose [A] parameters are instantiated with regular subset types, since this is how we will use [sumor] below. *) | |
458 | |
459 Notation "!!" := (inright _ _). | |
460 Notation "[[[ x ]]]" := (inleft _ [x]). | |
461 | |
462 (** Now we are ready to give the final version of possibly-failing predecessor. The [sumor]-based type that we use is maximally expressive; any implementation of the type has the same input-output behavior. *) | |
463 | |
464 Definition pred_strong7 (n : nat) : {m : nat | n = S m} + {n = 0}. | |
465 refine (fun n => | |
466 match n return {m : nat | n = S m} + {n = 0} with | |
467 | O => !! | |
468 | S n' => [[[n']]] | |
469 end); trivial. | |
470 Defined. | |
471 | |
472 | |
473 (** * Monadic Notations *) | |
474 | |
475 (** We can treat [maybe] like a monad, in the same way that the Haskell [Maybe] type is interpreted as a failure monad. Our [maybe] has the wrong type to be a literal monad, but a "bind"-like notation will still be helpful. *) | |
431 | 476 |
432 Notation "x <- e1 ; e2" := (match e1 with | 477 Notation "x <- e1 ; e2" := (match e1 with |
433 | Unknown => ?? | 478 | Unknown => ?? |
434 | Found x _ => e2 | 479 | Found x _ => e2 |
435 end) | 480 end) |
436 (right associativity, at level 60). | 481 (right associativity, at level 60). |
437 | 482 |
438 Notation "e1 ;; e2" := (if e1 then e2 else ??) | 483 (** The meaning of [x <- e1; e2] is: First run [e1]. If it fails to find an answer, then announce failure for our derived computation, too. If [e1] %\textit{%#<i>#does#</i>#%}% find an answer, pass that answer on to [e2] to find the final result. The variable [x] can be considered bound in [e2]. |
439 (right associativity, at level 60). | 484 |
485 This notation is very helpful for composing richly-typed procedures. For instance, here is a very simple implementation of a function to take the predecessors of two naturals at once. *) | |
486 | |
487 Definition doublePred (n1 n2 : nat) : {{p | n1 = S (fst p) /\ n2 = S (snd p)}}. | |
488 refine (fun n1 n2 => | |
489 m1 <- pred_strong6 n1; | |
490 m2 <- pred_strong6 n2; | |
491 [[(m1, m2)]]); tauto. | |
492 Defined. | |
493 | |
494 (** We can build a [sumor] version of the "bind" notation and use it to write a similarly straightforward version of this function. *) | |
495 | |
496 (** printing <-- $\longleftarrow$ *) | |
497 | |
498 Notation "x <-- e1 ; e2" := (match e1 with | |
499 | inright _ => !! | |
500 | inleft (exist x _) => e2 | |
501 end) | |
502 (right associativity, at level 60). | |
503 | |
504 (** printing * $\times$ *) | |
505 | |
506 Definition doublePred' (n1 n2 : nat) : {p : nat * nat | n1 = S (fst p) /\ n2 = S (snd p)} | |
507 + {n1 = 0 \/ n2 = 0}. | |
508 refine (fun n1 n2 => | |
509 m1 <-- pred_strong7 n1; | |
510 m2 <-- pred_strong7 n2; | |
511 [[[(m1, m2)]]]); tauto. | |
512 Defined. | |
440 | 513 |
441 | 514 |
442 (** * A Type-Checking Example *) | 515 (** * A Type-Checking Example *) |
443 | 516 |
444 Inductive exp : Set := | 517 Inductive exp : Set := |
464 -> hasType (And e1 e2) TBool. | 537 -> hasType (And e1 e2) TBool. |
465 | 538 |
466 Definition eq_type_dec : forall (t1 t2 : type), {t1 = t2} + {t1 <> t2}. | 539 Definition eq_type_dec : forall (t1 t2 : type), {t1 = t2} + {t1 <> t2}. |
467 decide equality. | 540 decide equality. |
468 Defined. | 541 Defined. |
542 | |
543 Notation "e1 ;; e2" := (if e1 then e2 else ??) | |
544 (right associativity, at level 60). | |
469 | 545 |
470 Definition typeCheck (e : exp) : {{t | hasType e t}}. | 546 Definition typeCheck (e : exp) : {{t | hasType e t}}. |
471 Hint Constructors hasType. | 547 Hint Constructors hasType. |
472 | 548 |
473 refine (fix F (e : exp) : {{t | hasType e t}} := | 549 refine (fix F (e : exp) : {{t | hasType e t}} := |
490 Defined. | 566 Defined. |
491 | 567 |
492 Eval simpl in typeCheck (Nat 0). | 568 Eval simpl in typeCheck (Nat 0). |
493 Eval simpl in typeCheck (Plus (Nat 1) (Nat 2)). | 569 Eval simpl in typeCheck (Plus (Nat 1) (Nat 2)). |
494 Eval simpl in typeCheck (Plus (Nat 1) (Bool false)). | 570 Eval simpl in typeCheck (Plus (Nat 1) (Bool false)). |
571 | |
572 Print sumor. | |
573 | |
574 | |
575 | |
576 Notation "e1 ;;; e2" := (if e1 then e2 else !!) | |
577 (right associativity, at level 60). | |
578 | |
579 Theorem hasType_det : forall e t1, | |
580 hasType e t1 | |
581 -> forall t2, | |
582 hasType e t2 | |
583 -> t1 = t2. | |
584 induction 1; inversion 1; crush. | |
585 Qed. | |
586 | |
587 Definition typeCheck' (e : exp) : {t : type | hasType e t} + {forall t, ~hasType e t}. | |
588 Hint Constructors hasType. | |
589 Hint Resolve hasType_det. | |
590 | |
591 refine (fix F (e : exp) : {t : type | hasType e t} + {forall t, ~hasType e t} := | |
592 match e return {t : type | hasType e t} + {forall t, ~hasType e t} with | |
593 | Nat _ => [[[TNat]]] | |
594 | Plus e1 e2 => | |
595 t1 <-- F e1; | |
596 t2 <-- F e2; | |
597 eq_type_dec t1 TNat;;; | |
598 eq_type_dec t2 TNat;;; | |
599 [[[TNat]]] | |
600 | Bool _ => [[[TBool]]] | |
601 | And e1 e2 => | |
602 t1 <-- F e1; | |
603 t2 <-- F e2; | |
604 eq_type_dec t1 TBool;;; | |
605 eq_type_dec t2 TBool;;; | |
606 [[[TBool]]] | |
607 end); clear F; crush' tt hasType; eauto. | |
608 Defined. | |
609 | |
610 Eval simpl in typeCheck' (Nat 0). | |
611 Eval simpl in typeCheck' (Plus (Nat 1) (Nat 2)). | |
612 Eval simpl in typeCheck' (Plus (Nat 1) (Bool false)). |