Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I want to understand how expressions work in Ocaml.
For example, I have :
type expr =
Int of int
| Var of string
| Sum of expr * expr
| Diff of expr * expr
| Mult of expr * expr
| Div of expr * expr
How can I recognise if an element is an expression?
I was think to something like expr -> expr -> bool :
let subexpression express1 express2 =
if express1 express1 then true else false
let E1 = 3 x 8 in
let E2 = 5/6 in
if subexpression E1 E2 then print_strin "true" else print_string "false"
I haven't test the code because this is what I'm thinking, but actually I don't know how to write it...
You need to be clear on whether you're asking about expressions in OCaml generally or values of the type expr that you define here.
Because OCaml is a strongly typed language, you can't have a value of type expr that's not well formed. So there's no meaningful function to test whether something of type expr is an expression. (You could define a function that always returns true.)
On the other hand, your proposed function has two expression parameters. This doesn't make a lot of sense either. What is the purpose of these two parameters?
Other parts of your question suggest that you want to determine whether one expression is a subexpression of another. That's a different question entirely.
You can look through an value of type expr by working recursively through the different cases. The basic framework of a function for traversing such a value would look something like this:
let myfunc expr =
match expr with
| Int n -> (* do something n, an int *)
| Var s -> (* do something with s, a string *)
| Sum (e1, e2) -> some_combination_of (myfunc e1) (myfunc e2)
| Diff (e1, e2) -> some_combination_of (myfunc e1) (myfunc e2)
| Mult (e1, e2) -> some_combination_of (myfunc e1) (myfunc e2)
| Div (e1, e2) -> some_combination_of (myfunc e1) (myfunc e2)
It's hard to say more than this because your question is hard to understand, (and it frankly doesn't look like you've put in very much work on it yet).
Related
I am trying to implement a basic parser, scanner, and a minimal language in OCaml. I believe the issue is that I'm trying to maintain a map between variables in this toy language and their values, and the language should be able to handle an expression like a=2;a and return 2. The name seems to successfully store the number 2, but by the time the program moves on to evaluating the second expression, it does not find the name in the map. And I can't understand why.
Below is the abstract syntax tree.
Ast.ml
type operator = Add (* for now just one operator *)
type expr =
Binop of expr * operator * expr
| Lit of int (* a number *)
| Seq of expr * expr (* a sequence, to behave like ";" *)
| Asn of string * expr (* assignment, to behave like "=" in an imperative language *)
| Var of string (* a variable *)
Here are the parser and scanner.
parser.mly
%{
open Ast
%}
%token SEQ PLUS ASSIGN EOF
%token <int> LITERAL
%token <string> VARIABLE
%left SEQ PLUS
%start expr
%type <Ast.expr> expr
%%
expr:
| expr SEQ expr { Seq($1, $3) }
| expr PLUS expr { Binop($1, Add, $3) }
| LITERAL { Lit($1) }
| VARIABLE { Var($1) }
| VARIABLE ASSIGN expr { Asn($1, $3) }
scanner.mll
{
open Parser
}
rule tokenize = parse
[' ' '\t' '\r' '\n'] { tokenize lexbuf }
| '+' { PLUS }
| ['0'-'9']+ as lit { LITERAL(int_of_string lit) }
| ['a'-'z']+ as id { VARIABLE(id) }
| '=' { ASSIGN }
| ';' { SEQ }
| eof { EOF }
And here's where I tried to implement a sort of name-space in a basic calculator.
calc.ml
open Ast
module StringMap = Map.Make(String)
let namespace = ref StringMap.empty
let rec eval exp = match exp with
| Lit(n) -> n
| Binop(e1, op, e2) ->
let v1 = eval e1 in
let v2 = eval e2 in
v1+v2
| Asn (name, e) ->
let v = eval e in
(namespace := StringMap.add name v !namespace; v)
| Var(name) -> StringMap.find name !namespace
| Seq(e1, e2) ->
(let _ = eval e1 in
eval e2)
let _ =
let lexbuf = Lexing.from_channel stdin in
let expr = Parser.expr Scanner.tokenize lexbuf in
let result = eval expr in
print_endline (string_of_int result)
To test it out I compile, and it compiles successfully, then run $ ./calc in a terminal, and enter a=2;a then press Ctrl+D. It should print 2 but it gives a Not found exception. Presumably this is coming from the StringMap.find line, and it's not finding the name in the namespace. I've tried throwing print lines around, and I think I can confirm that the sequence is being correctly processed in the terminal and that the first evaluation is happening successfully, with the name and value getting entered into the string map. But for some reason it seems not to be there when the program moves on to processing the second expression in the sequence.
I'd appreciate any clarification, thanks.
I cannot reproduce your error.
Feeding the AST directly to eval
let () =
let ast = Seq(Asn ("a", Lit 2),Var "a") in
let result = eval ast in
print_endline (string_of_int result)
prints 2 as expected.
After fixing your parser to recognize the end of the stream:
entry:
| expr EOF { $1 }
using it in
let () =
let s = Lexing.from_string "a=2;a\n" in
let ast = Parser.entry Scanner.tokenize s in
let result = eval ast in
print_endline (string_of_int result)
prints 2 as expected. And without this fix, your code fails with a syntax error.
EDIT:
Rather than using a makefile, I will advise to use dune, with the following simple dune file:
(menhir (modules parser))
(ocamllex scanner)
(executable (name calc))
it will at least solve your compilation troubles.
Hey so I don't know if you are still looking for the solution, but I was able to reproduce the problem and how I solved it was simply adding assign to the %left statement in parser.mly
%left SEQ ASSIGN PLUS
I have recently started working on OCAML. I am working from the book Modern Programming Languages, 2nd ed. The first chapter on ML has an exercise requiring the definition of a function max of type int list -> int to return the largest element from a list of integers. There is additionally a hint which suggests the inclusion of a helper function maxhelper which as a second parameter takes the current largest element. Then max is defined as :
fun max x = maxhelper (tl x, hd x)
I am trying to implement this in OCAML. Here is my code :
let max x =
let rec maxhelper x cur_max =
match x with
| [] -> cur_max
| h::t ->
if cur_max < h then maxhelper t h
else maxhelper t cur_max
in maxhelper List.tl(x) List.hd(x)
;;
This results in an error I cannot understand : This expression, i.e. List.tl(x) on the last line has type 'a list -> 'a list
but an expression was expected of type ('b -> 'c -> 'd) list
What puzzles me is when I write the maxhelper function separately and give it arguments [2;3;4] 1 (original list being [1;2;3;4]) it works correctly. Further, if I replace the arguments provided under in as
in maxhelper x 0
The code compiles and works correctly (for non-negative numbers). I am not sure what I have missed regarding passing arguments to in, or the error message I received. Mainly, why does the additional of a List() call cause an error?
You're writing function calls as in an Algolic language, that's the basic problem I think.
Instead of
maxhelper List.tl(x) List.hd(x)
You should have
maxhelper (List.tl x) (List.hd x)
The way you wrote it, there are 4 parameters being passed to maxhelper: List.tl, x, List.hd, x.
Suppose I have an expression like :(Main.i / (0.5 * Main.i * sin(Main.i)).
I would like to replace each occurence of Main.i into some other symbol. Is there an idiomatic way to do this in Julia?
Main.i is not a symbol but an expression, which you can check by doing dump(:(Main.i)).
Here is a quick writeup what I think might match your needs:
function expr_replace(expr, old, new)
expr == old && return new
if expr isa Expr
expr = deepcopy(expr) # to avoid mutation of source
for i in eachindex(expr.args)
expr.args[i] = expr_replace(expr.args[i], old, new)
end
end
expr
end
Does it work for you?
EDIT: Here is a version that does a minimal safe use of deepcopy:
function expr_replace(expr, old, new)
function f(expr)
expr == old && return deepcopy(new)
if expr isa Expr
for i in eachindex(expr.args)
expr.args[i] = f(expr.args[i])
end
end
expr
end
f(deepcopy(expr))
end
In general I guess this will not matter that much as you probably will not want to pass 100 lines of code through this function.
Idiomatic F# can nicely represent the classic recursive expression data structure:
type Expression =
| Number of int
| Add of Expression * Expression
| Multiply of Expression * Expression
| Variable of string
together with recursive functions thereon:
let rec simplify_add (exp: Expression): Expression =
match exp with
| Add (x, Number 0) -> x
| Add (Number 0, x) -> x
| _ -> exp
... oops, that doesn't work as written; simplify_add needs to recur into subexpressions. In this toy example that's easy enough to do, only a couple of extra lines of code, but in a real program there would be dozens of expression types; one would prefer to avoid adding dozens of lines of boilerplate to every function that operates on expressions.
Is there any way to express 'by default, recur on subexpressions'? Something like:
let rec simplify_add (exp: Expression): Expression =
match exp with
| Add (x, Number 0) -> x
| Add (Number 0, x) -> x
| _ -> recur simplify_add exp
where recur might perhaps be some sort of higher-order function that uses reflection to look up the type definition or somesuch?
Unfortunately, F# does not give you any recursive function for processing your data type "for free". You could probably generate one using reflection - this would be valid if you have a lot of recursive types, but it might not be worth it in normal situations.
There are various patterns that you can use to hide the repetition though. One that I find particularly nice is based on the ExprShape module from standard F# libraries. The idea is to define an active pattern that gives you a view of your type as either leaf (with no nested sub-expressions) or node (with a list of sub-expressions):
type ShapeInfo = Shape of Expression
// View expression as a node or leaf. The 'Shape' just stores
// the original expression to keep its original structure
let (|Leaf|Node|) e =
match e with
| Number n -> Leaf(Shape e)
| Add(e1, e2) -> Node(Shape e, [e1; e2])
| Multiply(e1, e2) -> Node(Shape e, [e1; e2])
| Variable s -> Leaf(Shape e)
// Reconstruct an expression from shape, using new list
// of sub-expressions in the node case.
let FromLeaf(Shape e) = e
let FromNode(Shape e, args) =
match e, args with
| Add(_, _), [e1; e2] -> Add(e1, e2)
| Multiply(_, _), [e1; e2] -> Multiply(e1, e2)
| _ -> failwith "Wrong format"
This is some boilerplate code that you'd have to write. But the nice thing is that we can now write the recursive simplifyAdd function using just your special cases and two additional patterns for leaf and node:
let rec simplifyAdd exp =
match exp with
// Special cases for this particular function
| Add (x, Number 0) -> x
| Add (Number 0, x) -> x
// This now captures all other recursive/leaf cases
| Node (n, exps) -> FromNode(n, List.map simplifyAdd exps)
| Leaf _ -> exp
I have a boolean abstract syntax tree
type bast =
True
| False
| Not of bast
| Or of bast * bast
| And of bast * bast
and I want to apply on it a function and get all the subtrees that return true for this function.
My try:
let findtrees f (ast: bast ) =
let rec findtree (tree: bast ) (mylist: bast list) = match tree with
| True ->
if (f tree)=true then mylist#[tree] else []
| False ->
if (f tree)=true then mylist#[tree] else []
| Not e -> Not (findtree e subtrees)
| And (e1,e2) -> And (findtree e1 mylist, findtree e2 mylist)
| Or (e1,e2) -> Or (findtree e1 mylist, findtree e2 mylist)
in findtree ast []
I get an error:
Error: The variant type list has no constructor Not
Tried also with this:
let findtrees f (ast: bast) =
let rec findtree (tree: bast) (mylist: bast list) = match tree with
(True|False) -> mylist
| subtree ->
if (f subtree)=true then
mylist#[subtree]
else
select_tree subtree mylist
in findtree ast []
Compiles fine but never terminates!
first of all, it shouldn't compile, since Bast should be lowercased.
That is because you return a value of type list on first two cases, and an atom on a latter three. Moreover, (compiler didn't mentioned it yet, but will soon) Not constructor accepts a bast, but you're trying to create it with a bast list
Here's what I would probably write as a first working attempt:
let findtrees f (ast: bast ) =
let rec findtree tree mylist =
let mylist = if f tree then tree::mylist else mylist in
match tree with
| True| False -> mylist
| Not e -> findtree e mylist
| Or (e1,e2)
| And (e1,e2) -> findtree e2 ## findtree e1 mylist
in findtree ast []
Some remarks:
You don't need to write exp = true for any expression exp (in your case it was f tree), since it implies that that exp is of type boolean and the resulting value would be exactly the same (please write the truth table to verify that)
I replaced mylist#[tree] with tree::mylist which is faster, but will produce a list in reverse order. If you care about that order, and wish to have the latest tested tree at the end of the list, simply apply List.rev to the result (you may of course include that in the body of findtrees)
Because your tree represents boolean expressions, there's perhaps a better way of handling the problem you are trying to solve.