From 080e7b87fa67f52b0892e18a750b68f84b378110 Mon Sep 17 00:00:00 2001 From: Mikail Khan Date: Thu, 21 Oct 2021 22:54:10 -0400 Subject: [PATCH] wildcard pattern --- README.md | 2 ++ examples/euler1.rsc | 2 +- examples/euler2.rsc | 8 ++++++++ examples/euler3.rsc | 44 ++++++++++++++++++++++++++++++++++++++++++++ lib/eval.ml | 3 +++ lib/operators.ml | 4 +++- lib/parser.ml | 9 +++++---- lib/scanner.ml | 8 ++++++-- lib/types.ml | 5 ++++- test/euler.ml | 8 ++++++++ 10 files changed, 84 insertions(+), 9 deletions(-) create mode 100644 examples/euler2.rsc create mode 100644 examples/euler3.rsc diff --git a/README.md b/README.md index 79b91da..45ac60d 100644 --- a/README.md +++ b/README.md @@ -115,3 +115,5 @@ let sum = { let predicate = fn(n) => (n % 3 == 0) || (n % 5 == 0) inspect(sum(filter(predicate, range(1, 1000)))) # 233168 ``` + +More project euler problems can be found in the [examples folder](https://github.com/mkhan45/RustScript2/tree/main/examples). diff --git a/examples/euler1.rsc b/examples/euler1.rsc index dcb3295..eda1b24 100644 --- a/examples/euler1.rsc +++ b/examples/euler1.rsc @@ -7,7 +7,7 @@ let range = { let filter = { let helper = fn(f, ls, acc) => match ls - | (hd, ()) -> acc + | (_, ()) -> acc | (hd, tl) -> if f(hd) then helper(f, tl, (hd, acc)) diff --git a/examples/euler2.rsc b/examples/euler2.rsc new file mode 100644 index 0000000..8cc78f9 --- /dev/null +++ b/examples/euler2.rsc @@ -0,0 +1,8 @@ +let euler2 = { + let aux = fn((a, b), acc) => + if b < 4000000 + then aux((b, a + 4 * b), acc + b) + else acc + + aux((0, 2), 0) +} diff --git a/examples/euler3.rsc b/examples/euler3.rsc new file mode 100644 index 0000000..73fac38 --- /dev/null +++ b/examples/euler3.rsc @@ -0,0 +1,44 @@ +let gcd = fn(a, b) => match (a, b) + | (0, b) -> b + | (a, 0) -> a + | (a, b) -> { + if a > b then { + gcd(b, a) + } else { + let remainder = b % a + if remainder != 0 then (gcd(a, remainder)) else a + } + } + +let pollard = fn(n) => match n + | 1 -> () + | n -> if n % 2 == 0 then { + 2 + } else { + let g = fn(x, n) => (x * x + 1) % n + let iter = fn(x, y, d) => match (x, y, d) + | (x, y, 1) -> { + let x = g(x, n) + let y = g(g(y, n), n) + let d = gcd(if (x > y) then (x - y) else (y - x), n) + iter(x, y, d) + } + | (_, _, d) -> if d == n then () else d + + iter(2, 2, 1) + } + +let largest_factor = fn(n) => { + let d = pollard(n) + if d == () then () else n / d +} + +let euler3 = { + # repeatedly factors until largest is found + let aux = fn(n) => match largest_factor(n) + | () -> n + | f -> if n == f then f else aux(f) + + let n = 600851475143 + aux(n) +} diff --git a/lib/eval.ml b/lib/eval.ml index 01f12ab..58ec328 100644 --- a/lib/eval.ml +++ b/lib/eval.ml @@ -22,10 +22,12 @@ let rec bind lhs rhs = (string_of_val (Tuple rhs_ls)) (List.length rhs_ls); assert false end + | WildcardPat, _ -> fun state -> state | _ -> assert false let rec pattern_matches pat value = match pat, value with + | WildcardPat, _ -> true | SinglePat _, _ -> true | NumberPat lhs, Number rhs -> Float.equal lhs rhs @@ -147,6 +149,7 @@ and eval_expr: expr -> ?tc:bool -> state -> value * state = | Binary ({op = Mul; _} as e) -> eval_op val_mul e.lhs e.rhs | Binary ({op = Div; _} as e) -> eval_op val_div e.lhs e.rhs | Binary ({op = EQ; _} as e) -> eval_op val_eq e.lhs e.rhs + | Binary ({op = NEQ; _} as e) -> eval_op val_neq e.lhs e.rhs | Binary ({op = LT; _} as e) -> eval_op val_lt e.lhs e.rhs | Binary ({op = GT; _} as e) -> eval_op val_gt e.lhs e.rhs | Binary ({op = And; _} as e) -> eval_op val_and e.lhs e.rhs diff --git a/lib/operators.ml b/lib/operators.ml index 10ba483..f6538ff 100644 --- a/lib/operators.ml +++ b/lib/operators.ml @@ -37,7 +37,9 @@ let rec val_eq lhs rhs = match lhs, rhs with in Boolean res else Boolean false - | _ -> assert false + | _ -> Boolean false + +let val_neq lhs rhs = Boolean (not (val_is_true (val_eq lhs rhs))) let val_lt lhs rhs = match lhs, rhs with | Number lhs, Number rhs -> Boolean (Float.compare lhs rhs < 0) diff --git a/lib/parser.ml b/lib/parser.ml index 126eb0b..29581b8 100644 --- a/lib/parser.ml +++ b/lib/parser.ml @@ -4,9 +4,9 @@ open Printf open Base let op_bp = function - | EQ -> (1, 2) - | And | Or -> (3, 4) - | LT | GT -> (5, 6) + | EQ | NEQ -> (1, 2) + | And | Or -> (3, 4) + | LT | GT -> (5, 6) | Add | Sub -> (7, 8) | Mul | Div | Mod -> (9, 10) @@ -57,8 +57,9 @@ and parse_pat ls = match ls with in (TuplePat (List.rev parsed), remaining) | (Ident s)::xs -> (SinglePat s, xs) | (Number f)::xs -> (NumberPat f, xs) + | Underscore::xs -> (WildcardPat, xs) | _ -> - print_toks ls; + printf "Expected pattern, got %s" (string_of_toks ls); assert false and parse_let ls = diff --git a/lib/scanner.ml b/lib/scanner.ml index cd5276e..12cb362 100644 --- a/lib/scanner.ml +++ b/lib/scanner.ml @@ -24,6 +24,7 @@ type token = | Hashtag | Comma | Pipe + | Underscore let is_numeric d = Base.Char.is_digit d || phys_equal d '.' let is_identic c = Base.Char.is_alphanum c || phys_equal c '_' @@ -66,19 +67,21 @@ and scan_ls = function | '&'::'&'::xs -> Operator And :: scan_ls xs | '|'::'|'::xs -> Operator Or :: scan_ls xs | '='::'='::xs -> Operator EQ :: scan_ls xs + | '!'::'='::xs -> Operator NEQ :: scan_ls xs | '%'::xs -> Operator Mod :: scan_ls xs | '('::xs -> LParen :: scan_ls xs | ')'::xs -> RParen :: scan_ls xs | '{'::xs -> LBrace :: scan_ls xs | '}'::xs -> RBrace :: scan_ls xs | '='::xs -> Equal :: scan_ls xs + | '_'::xs -> Underscore :: scan_ls xs | ','::xs -> Comma :: scan_ls xs | '#'::xs -> Hashtag :: scan_ls xs | '|'::xs -> Pipe :: scan_ls xs | 'T'::xs -> True :: scan_ls xs | 'F'::xs -> False :: scan_ls xs - | d::_ as ls when Base.Char.is_digit d -> scan_digit ls - | i::_ as ls when not (Base.Char.is_digit i) -> scan_ident ls + | d::_ as ls when Char.is_digit d -> scan_digit ls + | i::_ as ls when Char.is_alpha i -> scan_ident ls | ls -> printf "Scan Error: %s\n" (String.of_char_list ls); assert false @@ -118,6 +121,7 @@ let string_of_tok = function | Pipe -> "Pipe" | Match -> "Match" | MatchArrow -> "MatchArrow" + | Underscore -> "Underscore" let string_of_toks ls = String.concat ~sep:" " (List.map ~f:string_of_tok ls) let print_toks ls = ls |> string_of_toks |> printf "%s\n" diff --git a/lib/types.ml b/lib/types.ml index dd516ce..cde828d 100644 --- a/lib/types.ml +++ b/lib/types.ml @@ -9,6 +9,7 @@ type operator = | LT | GT | EQ + | NEQ | And | Or | Mod @@ -17,6 +18,7 @@ type pattern = | SinglePat of string | NumberPat of float | TuplePat of pattern list + | WildcardPat and state = (string, value, String.comparator_witness) Map.t @@ -67,4 +69,5 @@ let rec string_of_expr = function and string_of_pat = function | SinglePat s -> s | NumberPat f -> Float.to_string f - | TuplePat ls -> "(" ^ (String.concat ~sep:", " (List.map ~f:string_of_pat ls)) ^ ")" + | TuplePat ls -> sprintf "(%s)" (String.concat ~sep:", " (List.map ~f:string_of_pat ls)) + | WildcardPat -> "_" diff --git a/test/euler.ml b/test/euler.ml index a55ce09..db96c38 100644 --- a/test/euler.ml +++ b/test/euler.ml @@ -9,4 +9,12 @@ let () = Map.empty (module String) |> run_file (test_file "euler1.rsc") in assert_equal_expressions "sum(filter(predicate, range(1, 1000)))" "233168" state; + let state = + Map.empty (module String) |> run_file (test_file "euler2.rsc") in + assert_equal_expressions "euler2" "4613732" state; + + let state = + Map.empty (module String) |> run_file (test_file "euler3.rsc") in + assert_equal_expressions "euler3" "6857" state; + printf "Passed\n"