# Write an evaluator based on the grammar from ‹t3/lisp.py›. The # basic semantic rules are as follows: the first item in a compound # expression is always an identifier, and the compound expression # itself is interpreted as a function application. Evaluation is # eager, i.e. innermost applications are evaluated first. Literals # evaluate to themselves, i.e. ‹3.14› becomes a ‹real› with the # value ‹3.14›. Only numeric literals are relevant in this homework, # and all numeric literals represent reals (floats). Besides # literals, implement the following objects: # # • ‹(vector +)› where + means 1 or more objects of # type ‹real› # • ‹(matrix +)› where each vector is one row, starting # from the top # # And these operations on them: # # • ‹(+ )› vector addition, returns a ‹vector› # • ‹(dot )› dot product, returns a ‹real› # • ‹(cross )› cross product, returns a ‹vector› # • ‹(+ )› matrix addition, returns a ‹matrix› # • ‹(* )› matrix multiplication, returns a ‹matrix› # • ‹(det )› determinant, returns a ‹real› # • ‹(solve )› solve a system of linear equations, returns # a ‹vector› # # For ‹solve›, the argument is a matrix of coefficients and the result # is an assignment of variables -- if there are multiple solutions, # return a non-zero one. # # system │ matrix │ written as # x + y = 0 │ 1 1 │ (matrix (vector 1 1) # -y = 0 │ 0 -1 │ (vector 0 -1)) # # Expressions with argument type mismatches (both in object # constructors and in operations), attempts to construct a matrix # where the individual vectors (rows) are not of the same length, # addition of differently-shaped matrices, multiplication of # incompatible matrices, addition or dot product of different-sized # vectors, and so on, should evaluate to an ‹error› object. Attempt to # get a cross product of vectors with dimension other than 3 is an # ‹error›. Any expression with an ‹error› as an argument is also an # ‹error›. # # The evaluator should be available as ‹evaluate()› and take a string # for an argument. The result should be an object with methods # ‹is_real()›, ‹is_vector()›, ‹is_matrix()› and ‹is_error()›. # Iterating vectors gives reals and iterating matrices gives # vectors. Both should also support indexing. ‹float(x)› for # ‹x.is_real()› should do the right thing. # # You can use ‹numpy› in this task (in addition to standard # modules).