···11+type expr =
22+ | Const of float
33+ | Var of string
44+ | Add of expr * expr
55+ | Sub of expr * expr
66+ | Mul of expr * expr
77+ | Div of expr * expr
88+ | Pow of expr * expr
99+ | Neg of expr
1010+ | Sin of expr
1111+ | Cos of expr
1212+ | Tan of expr
1313+ | Exp of expr
1414+ | Ln of expr
1515+1616+let rec to_string = function
1717+ | Const f ->
1818+ if Float.is_integer f then
1919+ string_of_int (int_of_float f)
2020+ else
2121+ string_of_float f
2222+ | Var s -> s
2323+ | Add (e1, e2) -> to_string_add e1 ^ " + " ^ to_string_add e2
2424+ | Sub (e1, e2) -> to_string e1 ^ " - " ^ to_string_paren e2
2525+ | Mul (e1, e2) -> to_string_mul e1 ^ "*" ^ to_string_mul e2
2626+ | Div (e1, e2) -> to_string_div e1 ^ "/" ^ to_string_paren e2
2727+ | Pow (e1, e2) -> to_string_atom e1 ^ "^" ^ to_string_pow_exp e2
2828+ | Neg e -> "-" ^ to_string_atom e
2929+ | Sin e -> "sin(" ^ to_string e ^ ")"
3030+ | Cos e -> "cos(" ^ to_string e ^ ")"
3131+ | Tan e -> "tan(" ^ to_string e ^ ")"
3232+ | Exp e -> "e^" ^ to_string_pow_exp e
3333+ | Ln e -> "ln(" ^ to_string e ^ ")"
3434+3535+and to_string_atom = function
3636+ | (Const _ | Var _ | Sin _ | Cos _ | Tan _ | Exp _ | Ln _) as e -> to_string e
3737+ | e -> "(" ^ to_string e ^ ")"
3838+3939+and to_string_mul = function
4040+ | (Const _ | Var _ | Pow _ | Sin _ | Cos _ | Tan _ | Exp _ | Ln _ | Mul _) as e -> to_string e
4141+ | e -> "(" ^ to_string e ^ ")"
4242+4343+and to_string_div = function
4444+ | (Const _ | Var _ | Pow _ | Sin _ | Cos _ | Tan _ | Exp _ | Ln _ | Mul _) as e -> to_string e
4545+ | e -> "(" ^ to_string e ^ ")"
4646+4747+and to_string_add = function
4848+ | (Add _ | Sub _) as e -> to_string e
4949+ | e -> to_string e
5050+5151+and to_string_pow_exp = function
5252+ | (Const _ | Var _ | Pow _) as e -> to_string e
5353+ | e -> "(" ^ to_string e ^ ")"
5454+5555+and to_string_paren = function
5656+ | (Add _ | Sub _) as e -> "(" ^ to_string e ^ ")"
5757+ | e -> to_string e
5858+5959+let rec simplify = function
6060+ | Const _ as c -> c
6161+ | Var _ as v -> v
6262+ | Add (e1, e2) -> simplify_add (simplify e1) (simplify e2)
6363+ | Sub (e1, e2) -> simplify_sub (simplify e1) (simplify e2)
6464+ | Mul (e1, e2) -> simplify_mul (simplify e1) (simplify e2)
6565+ | Div (e1, e2) -> simplify_div (simplify e1) (simplify e2)
6666+ | Pow (e1, e2) -> simplify_pow (simplify e1) (simplify e2)
6767+ | Neg e -> simplify_neg (simplify e)
6868+ | Sin e -> Sin (simplify e)
6969+ | Cos e -> Cos (simplify e)
7070+ | Tan e -> Tan (simplify e)
7171+ | Exp e -> simplify_exp (simplify e)
7272+ | Ln e -> Ln (simplify e)
7373+7474+and simplify_add e1 e2 =
7575+ match (e1, e2) with
7676+ | Const 0.0, e | e, Const 0.0 -> e
7777+ | Const a, Const b -> Const (a +. b)
7878+ | _ -> Add (e1, e2)
7979+8080+and simplify_sub e1 e2 =
8181+ match (e1, e2) with
8282+ | e, Const 0.0 -> e
8383+ | Const a, Const b -> Const (a -. b)
8484+ | _ -> Sub (e1, e2)
8585+8686+and simplify_mul e1 e2 =
8787+ match (e1, e2) with
8888+ | Const 0.0, _ | _, Const 0.0 -> Const 0.0
8989+ | Const 1.0, e | e, Const 1.0 -> e
9090+ | Const a, Const b -> Const (a *. b)
9191+ | Const a, Mul (Const b, e) -> simplify_mul (Const (a *. b)) e
9292+ | Mul (Const a, e), Const b -> simplify_mul (Const (a *. b)) e
9393+ | Const a, Mul (e1, Mul (Const b, e2)) ->
9494+ simplify_mul (Const (a *. b)) (Mul (e1, e2))
9595+ | Mul (Const a, e1), Mul (Const b, e2) ->
9696+ simplify_mul (Const (a *. b)) (Mul (e1, e2))
9797+ | (Sin _ | Cos _ | Tan _ | Exp _ | Ln _ | Pow _), Var _ ->
9898+ Mul (e2, e1)
9999+ | _ -> Mul (e1, e2)
100100+101101+and simplify_div e1 e2 =
102102+ match (e1, e2) with
103103+ | Const 0.0, _ -> Const 0.0
104104+ | e, Const 1.0 -> e
105105+ | Const a, Const b -> Const (a /. b)
106106+ | e1, e2 when e1 = e2 -> Const 1.0
107107+ | _ -> Div (e1, e2)
108108+109109+and simplify_pow e1 e2 =
110110+ match (e1, e2) with
111111+ | _, Const 0.0 -> Const 1.0
112112+ | e, Const 1.0 -> e
113113+ | Const 0.0, _ -> Const 0.0
114114+ | Const 1.0, _ -> Const 1.0
115115+ | Const a, Const b -> Const (a ** b)
116116+ | _ -> Pow (e1, e2)
117117+118118+and simplify_neg = function
119119+ | Const c -> Const (-.c)
120120+ | Neg e -> e
121121+ | e -> Neg e
122122+123123+and simplify_exp = function
124124+ | Const 0.0 -> Const 1.0
125125+ | Ln e -> e
126126+ | e -> Exp e
127127+128128+let rec diff var = function
129129+ | Const _ -> Const 0.0
130130+ | Var v -> if v = var then Const 1.0 else Const 0.0
131131+ | Add (e1, e2) -> simplify (Add (diff var e1, diff var e2))
132132+ | Sub (e1, e2) -> simplify (Sub (diff var e1, diff var e2))
133133+ | Mul (e1, e2) ->
134134+ simplify (Add (Mul (diff var e1, e2), Mul (e1, diff var e2)))
135135+ | Div (e1, e2) ->
136136+ let num = Sub (Mul (diff var e1, e2), Mul (e1, diff var e2)) in
137137+ let den = Pow (e2, Const 2.0) in
138138+ simplify (Div (num, den))
139139+ | Pow (e, Const n) ->
140140+ simplify (Mul (Mul (Const n, Pow (e, Const (n -. 1.0))), diff var e))
141141+ | Pow (e1, e2) ->
142142+ let term1 = Mul (e2, Mul (Pow (e1, Sub (e2, Const 1.0)), diff var e1)) in
143143+ let term2 = Mul (Pow (e1, e2), Mul (Ln e1, diff var e2)) in
144144+ simplify (Add (term1, term2))
145145+ | Neg e -> simplify (Neg (diff var e))
146146+ | Sin e -> simplify (Mul (Cos e, diff var e))
147147+ | Cos e -> simplify (Neg (Mul (Sin e, diff var e)))
148148+ | Tan e ->
149149+ let sec2 = Div (Const 1.0, Pow (Cos e, Const 2.0)) in
150150+ simplify (Mul (sec2, diff var e))
151151+ | Exp e -> simplify (Mul (Exp e, diff var e))
152152+ | Ln e -> simplify (Div (diff var e, e))
153153+154154+let rec diff_n var n expr =
155155+ if n <= 0 then expr
156156+ else diff_n var (n - 1) (diff var expr)
157157+158158+let partial vars expr =
159159+ List.fold_left (fun e v -> diff v e) expr vars
160160+161161+let rec to_latex = function
162162+ | Const f ->
163163+ if Float.is_integer f then
164164+ string_of_int (int_of_float f)
165165+ else
166166+ string_of_float f
167167+ | Var s -> s
168168+ | Add (e1, e2) -> to_latex e1 ^ " + " ^ to_latex e2
169169+ | Sub (e1, e2) -> to_latex e1 ^ " - " ^ to_latex_paren_latex e2
170170+ | Mul (e1, e2) -> to_latex_mul_latex e1 ^ to_latex_mul_latex e2
171171+ | Div (e1, e2) -> "\\frac{" ^ to_latex e1 ^ "}{" ^ to_latex e2 ^ "}"
172172+ | Pow (e1, e2) -> to_latex_atom_latex e1 ^ "^{" ^ to_latex e2 ^ "}"
173173+ | Neg e -> "-" ^ to_latex_atom_latex e
174174+ | Sin e -> "\\sin(" ^ to_latex e ^ ")"
175175+ | Cos e -> "\\cos(" ^ to_latex e ^ ")"
176176+ | Tan e -> "\\tan(" ^ to_latex e ^ ")"
177177+ | Exp e -> "e^{" ^ to_latex e ^ "}"
178178+ | Ln e -> "\\ln(" ^ to_latex e ^ ")"
179179+180180+and to_latex_atom_latex = function
181181+ | (Const _ | Var _) as e -> to_latex e
182182+ | e -> "(" ^ to_latex e ^ ")"
183183+184184+and to_latex_mul_latex = function
185185+ | (Const _ | Var _ | Pow _ | Sin _ | Cos _ | Tan _ | Exp _ | Ln _) as e -> to_latex e
186186+ | e -> "(" ^ to_latex e ^ ")"
187187+188188+and to_latex_paren_latex = function
189189+ | (Add _ | Sub _) as e -> "(" ^ to_latex e ^ ")"
190190+ | e -> to_latex e
191191+192192+let rec eval env = function
193193+ | Const f -> f
194194+ | Var v ->
195195+ (try List.assoc v env
196196+ with Not_found -> failwith ("unbound variable: " ^ v))
197197+ | Add (e1, e2) -> eval env e1 +. eval env e2
198198+ | Sub (e1, e2) -> eval env e1 -. eval env e2
199199+ | Mul (e1, e2) -> eval env e1 *. eval env e2
200200+ | Div (e1, e2) -> eval env e1 /. eval env e2
201201+ | Pow (e1, e2) -> eval env e1 ** eval env e2
202202+ | Neg e -> -.(eval env e)
203203+ | Sin e -> sin (eval env e)
204204+ | Cos e -> cos (eval env e)
205205+ | Tan e -> tan (eval env e)
206206+ | Exp e -> exp (eval env e)
207207+ | Ln e -> log (eval env e)
···11+type token =
22+ | Num of float
33+ | Var of string
44+ | Ident of string
55+ | Plus | Minus | Star | Slash | Caret
66+ | LParen | RParen
77+ | EOF
88+99+let is_digit c = c >= '0' && c <= '9'
1010+let is_alpha c = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
1111+let is_alphanum c = is_alpha c || is_digit c
1212+1313+let tokenize str =
1414+ let len = String.length str in
1515+ let rec aux i acc =
1616+ if i >= len then List.rev (EOF :: acc)
1717+ else
1818+ match str.[i] with
1919+ | ' ' | '\t' | '\n' -> aux (i + 1) acc
2020+ | '+' -> aux (i + 1) (Plus :: acc)
2121+ | '-' -> aux (i + 1) (Minus :: acc)
2222+ | '*' -> aux (i + 1) (Star :: acc)
2323+ | '/' -> aux (i + 1) (Slash :: acc)
2424+ | '^' -> aux (i + 1) (Caret :: acc)
2525+ | '(' -> aux (i + 1) (LParen :: acc)
2626+ | ')' -> aux (i + 1) (RParen :: acc)
2727+ | c when is_digit c || c = '.' ->
2828+ let j = ref (i + 1) in
2929+ while !j < len && (is_digit str.[!j] || str.[!j] = '.') do
3030+ incr j
3131+ done;
3232+ let num_str = String.sub str i (!j - i) in
3333+ aux !j (Num (float_of_string num_str) :: acc)
3434+ | c when is_alpha c ->
3535+ let j = ref (i + 1) in
3636+ while !j < len && is_alphanum str.[!j] do
3737+ incr j
3838+ done;
3939+ let id = String.sub str i (!j - i) in
4040+ let tok = if !j < len && str.[!j] = '(' then Ident id else Var id in
4141+ aux !j (tok :: acc)
4242+ | c -> failwith (Printf.sprintf "unexpected character: %c" c)
4343+ in
4444+ aux 0 []
···11+open Lexer
22+open Expr
33+44+type parse_state = { tokens : token list; mutable pos : int }
55+66+let peek state =
77+ if state.pos < List.length state.tokens then
88+ List.nth state.tokens state.pos
99+ else EOF
1010+1111+let advance state =
1212+ state.pos <- state.pos + 1
1313+1414+let expect state tok =
1515+ if peek state = tok then advance state
1616+ else failwith (Printf.sprintf "expected token")
1717+1818+let rec parse_expr state =
1919+ parse_additive state
2020+2121+and parse_additive state =
2222+ let left = ref (parse_multiplicative state) in
2323+ while peek state = Plus || peek state = Minus do
2424+ let op = peek state in
2525+ advance state;
2626+ let right = parse_multiplicative state in
2727+ left := if op = Plus then Add (!left, right) else Sub (!left, right)
2828+ done;
2929+ !left
3030+3131+and parse_multiplicative state =
3232+ let left = ref (parse_power state) in
3333+ while peek state = Star || peek state = Slash do
3434+ let op = peek state in
3535+ advance state;
3636+ let right = parse_power state in
3737+ left := if op = Star then Mul (!left, right) else Div (!left, right)
3838+ done;
3939+ !left
4040+4141+and parse_power state =
4242+ let left = parse_unary state in
4343+ if peek state = Caret then begin
4444+ advance state;
4545+ let right = parse_power state in
4646+ match left with
4747+ | Var "e" -> Exp right
4848+ | _ -> Pow (left, right)
4949+ end else left
5050+5151+and parse_unary state =
5252+ match peek state with
5353+ | Minus ->
5454+ advance state;
5555+ Neg (parse_unary state)
5656+ | _ -> parse_primary state
5757+5858+and parse_primary state =
5959+ match peek state with
6060+ | Num n ->
6161+ advance state;
6262+ Const n
6363+ | Var v ->
6464+ advance state;
6565+ Var v
6666+ | Ident "sin" ->
6767+ advance state;
6868+ expect state LParen;
6969+ let arg = parse_expr state in
7070+ expect state RParen;
7171+ Sin arg
7272+ | Ident "cos" ->
7373+ advance state;
7474+ expect state LParen;
7575+ let arg = parse_expr state in
7676+ expect state RParen;
7777+ Cos arg
7878+ | Ident "tan" ->
7979+ advance state;
8080+ expect state LParen;
8181+ let arg = parse_expr state in
8282+ expect state RParen;
8383+ Tan arg
8484+ | Ident "exp" ->
8585+ advance state;
8686+ expect state LParen;
8787+ let arg = parse_expr state in
8888+ expect state RParen;
8989+ Exp arg
9090+ | Ident "ln" ->
9191+ advance state;
9292+ expect state LParen;
9393+ let arg = parse_expr state in
9494+ expect state RParen;
9595+ Ln arg
9696+ | Ident "e" ->
9797+ advance state;
9898+ Const (exp 1.0)
9999+ | LParen ->
100100+ advance state;
101101+ let expr = parse_expr state in
102102+ expect state RParen;
103103+ expr
104104+ | _ -> failwith "unexpected token in primary"
105105+106106+let parse str =
107107+ let tokens = tokenize str in
108108+ let state = { tokens; pos = 0 } in
109109+ let expr = parse_expr state in
110110+ if peek state = EOF then expr
111111+ else failwith "unexpected tokens after expression"
···11+open Leibniz.Parser
22+open Leibniz.Expr
33+44+let () =
55+ let expr = parse "e^(x^2)" in
66+ let result = diff "x" expr in
77+ print_endline (to_string result)