Abstract syntax trees are a convenient way to represent a syntactic expression in a structured way. Let us consider arithmetic expressions formed by the following rules:
- an integer is an arithmetic expression
- if
lhs
andrhs
are arithmetic expressions thenlhs + rhs
is an arithmetic expression - if
lhs
andrhs
are arithmetic expressions thenlhs * rhs
is an arithmetic expression
Such an expression can be represented by a value of type exp
as defined in the given prelude (as well as the definition of 1 + 2 * 3
as an example).
-
Write the expression
2 * 2 + 3 * 3
in a variablemy_example
. -
Write a function
eval : exp -> int
that computes the value of an arithmetic expression. The evaluation rules are:- If the expression is an integer
x
, the evaluation isx
- If the expression is
lhs + rhs
andlhs
evaluates tox
and rhs evaluates toy
, then the evaluation isx + y
- If the expression is
lhs * rhs
andlhs
evaluates tox
and rhs evaluates toy
, then the evaluation isx * y
- If the expression is an integer
-
If an expression is of the form
a * b + a * c
thena * (b + c)
is a factorized equivalent expression. Write a functionfactorize : exp -> exp
that implements this transformation on its input exp if it has the shapea * b + a * c
or does nothing otherwise. -
Write the reverse transformation of factorize,
expand : exp -> exp
, which turns an expression of the shapea * (b + c)
intoa * b + a * c
. -
Implement a function
simplify: exp -> exp
which takes an expressione
and:- If
e
is of the shapee * 0
or0 * e
, returns the expression0
- If
e
is of the shapee * 1
or1 * e
, returns the expressione
- If
e
is of the shapee + 0
or0 + e
, returns the expressione
and does nothing otherwise.
- If
Remarks:
The symbols (a
, b
, c
and e
) can match any expressions, not just integers.
these are a syntactical rewritings, so two expressions are considered equal if and only if they are exactly the same expressions (simply use the =
operator to check that).
The rewritings have to be done on the first level of the expression only, not recursively and not deeper in the expression. If the toplevel expression does not match the expected pattern, simply return the expression untouched.
type exp =
| EInt of int
| EAdd of exp * exp
| EMul of exp * exp
let example =
EAdd (EInt 1, EMul (EInt 2, EInt 3))
let my_example =
"Replace this string with your example." ;;
let eval e =
"Replace this string with your implementation." ;;
let factorize e =
"Replace this string with your implementation." ;;
let expand e =
"Replace this string with your implementation." ;;
let simplify e =
"Replace this string with your implementation." ;;