type expr =
| Plus of expr * expr (* a + b *)
| Minus of expr * expr (* a - b *)
| Times of expr * expr (* a * b *)
| Divide of expr * expr (* a / b *)
| Var of string (* "x", "y", etc. *)
Having this type "expr" I wanted to know how can I work with a customizable number of variables depending on my needs, in this case, we know that Plus is (Expr * Expr) but what if I want to do to do : ( a + b + c) or (a * b * c), is it possible? I got this example at https://ocaml.org/learn/tutorials/data_types_and_matching.html
Since + is a binary operation, the usual representation of a + b + c is this:
Plus (Plus (Var "a", Var "b"), Var "c")
Related
I have this code with the following structure:
type regexp =
| V (* void *)
| E (* epsilon *)
| C of char (* char *)
| U of regexp * regexp (* a + b *)
| P of regexp * regexp (* a.b *)
| S of regexp (* a* *)
;;
How do I convert a string like this (a + b) * into an expression of type regexp S (U (C 'a', C 'b'))?
I'm trying to create a code generating DSL in OCaml, however I can't find many examples on what the code generation looks like. I would just like to see how to create code values in OCaml.
For example if I had a type like this:
let equation =
Add of int * int
| Sub of int * int
| Mul of int * int
| Div of int * int;;
and I want a function like this:
let write_code = function
| Add (x, y) -> // INSERT CODE "x + y" here
etc... how would this look?
I have looked at this example http://okmij.org/ftp/meta-programming/tutorial/power.ml but the characters .< >. are causing syntax errors when I try to compile.
The code generated will not need to be compiled or executed, but saved to a .c file for later use.
I would just like to see the basic structure for this simple example so I can apply it to a more complicated problem.
You can do like that :
type equation =
| Const of int
| Var of string
| Add of equation * equation
| Mul of equation * equation ;;
let rec c_string_of_equation = function
| Const i -> string_of_int i
| Var x -> x
| Add (e1, e2) ->
"(" ^ c_string_of_equation e1 ^ ") + (" ^ c_string_of_equation e2 ^ ")"
| Mul (e1, e2) ->
"(" ^ c_string_of_equation e1 ^ ") * (" ^ c_string_of_equation e2 ^ ")"
;;
Here you produce a string and after that you can write that string where you want.
I changed your expression type a bit to be more general.
The result string will contain too much parentheses, but it does not matter because the generated code is not targeted to humans but to a compiler.
You could use a buffer :
As it's written in the module :
This module implements buffers that automatically expand as necessary. It provides accumulative concatenation of strings in quasi-linear time (instead of quadratic time when strings are concatenated pairwise).
For example, you can write :
let equation =
| Add of int * int
| Sub of int * int
| Mul of int * int
| Div of int * int;;
let co = open_out filename
let buff = Buffer.create 11235
let write_code = function
| Add (x, y) -> Buffer.add_string buff (Printf.sprintf "%d + %d" x y)
| ... -> ...
let write c =
write_code c;
Buffer.output_buffer co buff
With
# Buffer.create;;
- : int -> Buffer.t = <fun>
# Buffer.add_string;;
- : Buffer.t -> string -> unit = <fun>
# Buffer.output_buffer;;
- : out_channel -> Buffer.t -> unit = <fun>
Notice that Buffer.add_string write the string at the end of the buffer ;-)
type expr = NUM of int
| PLUS of expr * expr
| MINUS of expr * expr
let rec calc expr1 =
match expr1 with
| NUM i -> NUM i
| PLUS (lexpr1, rexpr1) ->
(match lexpr1, rexpr1 with
| (*(NUM li1,NUM ri1) -> NUM li1+ri1*)
| (lexpr1', rexpr1') -> PLUS (calc lexpr1', calc rexpr1'))
It says
Error: This expression has type expr but an expression was expected of type int
I don't know why errors keep coming out
Ocaml in the line
NUM li1+ri1
first creates a NUM and then tries to add ri1. But since + operator applies only on ints and not at expr and int, it throws an error.
To fix this add ints first:
NUM (li1+ri1)
I need to create a function that returns the result of calculating expressions of a created type:
type expr =
VarX
| VarY
| Sine of expr
| Cosine of expr
| Average of expr * expr
| Times of expr * expr
| Thresh of expr * expr * expr * expr
here is what the function is supposed to do :
eval : expr * float * float -> float that takes an triple (e,x,y) and evaluates the expression e at the point x,y . x and y are going to be between -1 and 1 and the result of the function will be in the same interval. Once you have implemented the function, you should get the following behavior at the OCaml prompt:
# eval (Sine(Average(VarX,VarY)),0.5,-0.5);;
- :float = 0.0
Here is the function that I wrote it needs to return a float:
let rec eval (e,x,y) = match e with
VarX -> x*1.0
|VarY ->y*1.0
|Sine expr -> sin(pi* eval (expr,x,y))
|Cosine expr -> cos( pi* eval (expr,x,y))
|Average (expr1, expr2) -> (eval (expr1,x,y)+eval (expr2,x,y))/2.0
|Times (expr1, expr2) -> (eval (expr1,x,y))*(eval (expr2,x,y))
|Thresh (expr1, expr2, expr3, expr4) ->if((eval (expr1,x,y))<(eval (expr2,x,y)))then (eval (expr3,x,y)) else(eval (expr4,x,y));;
this is the error that i get,
Error: This expression has type float but an expression was expected of type
int
how do i make the function return a float, i know it needs to think that every return value for each case needs to be a float but im not sure how to do that
The operator for multiplying two floats is *.. The operator for adding two floats is +.. And, the operator for dividing two floats is /.
I need to convert an arithmetic sequence that uses
this type:
type expr =
VarX
| VarY
| Sine of expr
| Cosine of expr
| Average of expr * expr
| Times of expr * expr
| Thresh of expr * expr * expr * expr
here are the definitions for all the things in it:
e ::= x | y | sin (pi*e) | cos (pi*e) | ((e + e)/2) | e * e | (e<e ? e : e)
need to convert something like this:
exprToString (Thresh(VarX,VarY,VarX,(Times(Sine(VarX),Cosine(Average(VarX,VarY))))));;
to this:
string = "(x<y?x:sin(pi*x)*cos(pi*((x+y)/2)))"
I know I have to do this recursively by matching each expr with its appropriate string but Im not sure where the function begins matching or how to recurse through it. Any help or clues would be appreciated
Here is a simplified version of what you probably want:
type expr =
| VarX
| Sine of expr
let rec exprToString = function
| VarX -> "x"
| Sine e -> "sin(" ^ exprToString e ^ ")"
let () = print_endline (exprToString (Sine (Sine (Sine (Sine VarX)))))
It recurses over the AST nodes and create the string representation of the input by concatenating the string representations of the nodes.
This approach may not work nicely for bigger real world examples since:
String concatenation (^) creates a new string from two, this is slower than using some more appropriate data structure such as Buffer.t
Too many parentheses, ex, (2*(2*(2*2))), not 2*2*2*2. If you want minimize the number of parentheses, your algorithm must be aware of operator precedence and connectivity.