File: EvalWithExc.v

package info (click to toggle)
coq-ext-lib 0.13.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 808 kB
  • sloc: makefile: 44; python: 31; sh: 4; lisp: 3
file content (98 lines) | stat: -rw-r--r-- 2,798 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
Require Import Coq.Strings.String.
(** Require the monad definitions **)
Require Import ExtLib.Structures.Monads.
(** Use the instances for exceptions **)
Require Import ExtLib.Data.Monads.EitherMonad.
(** Strings will be used for error messages **)
Require Import ExtLib.Data.String.

Set Implicit Arguments.
Set Strict Implicit.

(** Syntax and values of a simple language **)
Inductive value : Type :=
| Int : nat -> value
| Bool : bool -> value.

Inductive exp : Type :=
| ConstI : nat -> exp
| ConstB : bool -> exp
| Plus : exp -> exp -> exp
| If : exp -> exp -> exp -> exp.

Section monadic.
  (** Going to work over any monad [m] that is:
   ** 1) a Monad, i.e. [Monad m]
   ** 2) has string-valued exceptions, i.e. [MonadExc string m]
   **)
  Variable m : Type -> Type.
  Context {Monad_m : Monad m}.
  Context {MonadExc_m : MonadExc string m}.

  (** Use the notation for monads **)
  Import MonadNotation.
  Local Open Scope monad_scope.

  (** Functions that get [nat] or [bool] values from a [value] **)
  Definition asInt (v : value) : m nat :=
    match v with
      | Int n => ret n
      | _ =>
        (** if we don't have an integer, signal an error using
         ** [raise] from the MoandExc instance
         **)
        raise ("expected integer got bool")%string
    end.

  Definition asBool (v : value) : m bool :=
    match v with
      | Bool b => ret b
      | _ => raise ("expected bool got integer")%string
    end.

  (** The main evaluator routine returns a [value], but since we are
   ** working in the [m] monad, we return [m value]
   **)
  Fixpoint eval' (e : exp) : m value :=
    match e with
        (** when there is no error, we can just return (i.e. [ret])
         ** the answer
         **)
      | ConstI i => ret (Int i)
      | ConstB b => ret (Bool b)
      | Plus l r =>
        (** evaluate the sub-terms to numbers **)
        l <- eval' l ;;
        l <- asInt l ;;
        r <- eval' r ;;
        r <- asInt r ;;
        (** Combine the result **)
        ret (Int (l + r))
      | If t tr fa =>
        (** evaluate the test condition to a boolean **)
        t <- eval' t ;;
        t <- asBool t ;;
        (** case split and perform the appropriate recursion **)
        if (t : bool) then
          eval' tr
        else
          eval' fa
    end.

End monadic.

(** Wrap the [eval] function up with the monad instance that we
 ** want to use
 **)
Definition eval : exp -> string + value :=
  eval' (m := sum string).

(** Some tests **)
Eval compute in eval (Plus (ConstI 1) (ConstI 2)).
Eval compute in eval (Plus (ConstI 1) (ConstB false)).

(** Other useful monads:
 ** * Reader - for handling lexicographic environments
 ** * State - for handling non-lexical state, like a heap
 ** * MonadFix - for handling unbounded recursion
 **)