From 537386d97bc864c9ebdd4f9f4d065258550d4685 Mon Sep 17 00:00:00 2001 From: Nathan Braswell Date: Sun, 1 Aug 2021 20:21:14 -0400 Subject: [PATCH] Extended foldl and foldr to be variadic, fixed foldr, and added pattern matching! --- collections.kp | 12 +++++----- k_prime.krak | 63 +++++++++++++++++++++++++++++++++++++++++++------- match.kp | 29 +++++++++++++++++++++++ match_test.kp | 41 ++++++++++++++++++++++++++++++++ 4 files changed, 131 insertions(+), 14 deletions(-) create mode 100644 match.kp create mode 100644 match_test.kp diff --git a/collections.kp b/collections.kp index 1d93851..5f20abd 100644 --- a/collections.kp +++ b/collections.kp @@ -1,12 +1,12 @@ (let ( - foldl (let (helper (rec-lambda recurse (f z v i) (if (= i (len v)) z - (recurse f (f z (idx v i)) v (+ i 1))))) - (lambda (f z v) (helper f z v 0))) - foldr (let (helper (rec-lambda recurse (f z v i) (if (= i (len v)) z - (f (idx v i) (recurse f z v (+ i 1)))))) - (lambda (f z v) (helper f z v 0))) + foldl (let (helper (rec-lambda recurse (f z vs i) (if (= i (len (idx vs 0))) z + (recurse f (lapply f (cons z (map (lambda (x) (idx x i)) vs))) vs (+ i 1))))) + (lambda (f z & vs) (helper f z vs 0))) + foldr (let (helper (rec-lambda recurse (f z vs i) (if (= i (len (idx vs 0))) z + (lapply f (cons (recurse f z vs (+ i 1)) (map (lambda (x) (idx x i)) vs)))))) + (lambda (f z & vs) (helper f z vs 0))) reverse (lambda (x) (foldl (lambda (acc i) (cons i acc)) [] x)) empty_dict [] put (lambda (m k v) (cons [k v] m)) diff --git a/k_prime.krak b/k_prime.krak index 5f790c8..427125e 100644 --- a/k_prime.krak +++ b/k_prime.krak @@ -115,7 +115,7 @@ obj KPBuiltinCombiner (Object) { copy_construct(&other) } fun operator==(other: ref KPBuiltinCombiner):bool { - return false + return name == other.name } fun call(params: vec, dynamic_env: KPValue): pair<*KPEnv, KPResult> { if !dynamic_env.is_env() { @@ -388,6 +388,17 @@ obj KPValue (Object) { } return false } + fun is_bool(): bool { + match (internal) { + KPValue_int::True() { + return true + } + KPValue_int::False() { + return true + } + } + return false + } fun is_truthy(): bool { match (internal) { KPValue_int::False() { @@ -839,13 +850,55 @@ fun main(argc: int, argv: **char): int { return make_pair(null(), KPResult::Ok(kpBool(params[0].is_symbol()))) })); - env->set(str("int?"), make_builtin_combiner(str("symbol?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { + env->set(str("int?"), make_builtin_combiner(str("int?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 { return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to int?")))) } return make_pair(null(), KPResult::Ok(kpBool(params[0].is_int()))) })); + env->set(str("string?"), make_builtin_combiner(str("string?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { + if params.size != 1 { + return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to string?")))) + } + return make_pair(null(), KPResult::Ok(kpBool(params[0].is_string()))) + })); + + env->set(str("combiner?"), make_builtin_combiner(str("combiner?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { + if params.size != 1 { + return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to combiner?")))) + } + return make_pair(null(), KPResult::Ok(kpBool(params[0].is_combiner()))) + })); + + env->set(str("env?"), make_builtin_combiner(str("env?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { + if params.size != 1 { + return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to env?")))) + } + return make_pair(null(), KPResult::Ok(kpBool(params[0].is_env()))) + })); + + env->set(str("nil?"), make_builtin_combiner(str("nil?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { + if params.size != 1 { + return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to nil?")))) + } + return make_pair(null(), KPResult::Ok(kpBool(params[0].is_nil()))) + })); + + env->set(str("bool?"), make_builtin_combiner(str("bool?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { + if params.size != 1 { + return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to bool?")))) + } + return make_pair(null(), KPResult::Ok(kpBool(params[0].is_bool()))) + })); + + env->set(str("array?"), make_builtin_combiner(str("array?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { + if params.size != 1 { + return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to array?")))) + } + return make_pair(null(), KPResult::Ok(kpBool(params[0].is_array()))) + })); + env->set(str("str-to-symbol"), make_builtin_combiner(str("str-to-symbol"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 { return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to str-to-symbol")))) @@ -869,12 +922,6 @@ fun main(argc: int, argv: **char): int { env->set(str("array"), make_builtin_combiner(str("array"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { return make_pair(null(), KPResult::Ok(kpArray(params))) })); - env->set(str("array?"), make_builtin_combiner(str("array?"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { - if params.size != 1 { - return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to array?")))) - } - return make_pair(null(), KPResult::Ok(kpBool(params[0].is_array()))) - })); env->set(str("len"), make_builtin_combiner(str("len"), 1, false, fun(params: vec, dynamic_env: *KPEnv): pair<*KPEnv, KPResult> { if params.size != 1 { return make_pair(null(), KPResult::Err(kpString(str("Need 1 param to len")))) diff --git a/match.kp b/match.kp new file mode 100644 index 0000000..368041c --- /dev/null +++ b/match.kp @@ -0,0 +1,29 @@ +(with_import "./collections.kp" +(let ( + + match (vau de (x & cases) (let ( + x (eval x de) + evaluate_case (rec-lambda recurse (name_dict x c) (cond + ; an explicit nil name_dict case allows us to simply fold over recurse in the array case later + (nil? name_dict) nil + (symbol? c) (put name_dict c x) + (and (int? x) (int? c) (= x c)) name_dict + (and (string? x) (string? c) (= x c)) name_dict + (and (bool? x) (bool? c) (= x c)) name_dict + (and (combiner? x) (combiner? c) (= x c)) name_dict + ; check for invocation of quote directly + ; not necessarily ideal if they define their own quote or something + (and (symbol? x) (array? c) (= 2 (len c)) (= quote (idx c 0)) (= x (idx c 1))) name_dict + ; ditto with above, but with array + (and (array? x) (array? c) (= (+ 1 (len x)) (len c)) (= array (idx c 0))) (foldl recurse name_dict x (slice c 1 -1)) + true nil + )) + + iter (rec-lambda recurse (x i cases) (if (>= i (len cases)) (error "none of match arms matched!") + (let ( mapping (evaluate_case empty_dict x (idx cases i))) + (if (!= nil mapping) (eval (idx cases (+ i 1)) (add-dict-to-env de mapping)) + (recurse x (+ i 2) cases))))) + ) (iter x 0 cases))) +) + (provide match) +)) diff --git a/match_test.kp b/match_test.kp new file mode 100644 index 0000000..0697476 --- /dev/null +++ b/match_test.kp @@ -0,0 +1,41 @@ +(with_import "./match.kp" +(do + (println "first " + (match 1 + 1 true + a (+ a 1) + )) + + (println "second " + (match 3 + 1 true + a (+ a 1) + )) + (println "third " + (match "str" + 1 true + "str" "It was a string!" + a (+ a 1) + )) + (println "fourth " + (match [ 1337 "str" ] + 1 true + "str" "It was a string!" + [ 1337 "str" ] "matched an array of int str" + a (+ a 1) + )) + (println "fifth " + (match [ 1337 "str" 'sy ] + 1 true + "str" "It was a string!" + [ 1337 "str" 'sy ] "matched an array of int str symbol" + a (+ a 1) + )) + (println "sixth " + (match [ 1337 "str" 'walla + 11 false 'kraken [ 'inner 'middle 'end ] [ 'inner1 'middle1 'end1 ] ] + 1 true + "str" "It was a string!" + [ 1337 "str" 'walla + a false b [ 'inner c 'end ] d ] (str "matched, and got " a b c d) + a (+ a 1) + )) +))