From a0f52c8755e48078cf7efa087031cbe9f2bd27cb Mon Sep 17 00:00:00 2001 From: Bobbi Towers Date: Fri, 8 Sep 2023 18:00:35 -0700 Subject: [PATCH] make `assoc` respect value semantics --- main.js | 40 ++-------------------------------------- scratch.clj | 9 ++++++++- src/clj/core.clj | 4 +--- src/clj/pprint.clj | 2 +- src/core.js | 2 +- src/types.js | 17 ++++++++++++++--- test/exercises.json | 2 +- 7 files changed, 28 insertions(+), 48 deletions(-) diff --git a/main.js b/main.js index 9fb5a4e..f7840da 100644 --- a/main.js +++ b/main.js @@ -7,43 +7,7 @@ import testSuites from './test/tests.json'; import { evalString, deftests, clearTests } from "./src/interpreter" let editorState = EditorState.create({ - doc: `(def mycolls - [[1 2] [3 4] [5 6] [7 8] [9 0]]) - -(def f str) -(def c0 [1 2]) -(def c1 [3 4]) -(def c2 [5 6]) -(def colls [[7 8] [9 0]]) - -(macroexpand - (map+ str [[1 2] [3 4] [5 6] [7 8] [9 0]])) - -(def colls mycolls) -(def f str) -(loop* [s0 (seq (nth colls 0)) s1 (seq (nth colls 1)) s2 (seq (nth colls 2)) s3 (seq (nth colls 3)) s4 (seq (nth colls 4)) res []] - (if (or (empty? s0) (empty? s1) (empty? s2) (empty? s3) (empty? s4)) - (apply list res) - (recur (rest s0) (rest s1) (rest s2) (rest s3) (rest s4) - (conj res (f (first s0) (first s1) (first s2) (first s3) (first s4)))))) - -(list* c0 c1 c2 colls) - -(map+ f (list* c0 c1 c2 colls)) - -(macroexpand - (map+ f (list* c0 c1 c2 colls))) - -(def f str) -(def colls [[1 2] [3 4] [5 6] [7 8] [9 0]]) - -(loop* [s0 (seq (nth colls 0)) s1 (seq (nth colls 1)) s2 (seq (nth colls 2)) s3 (seq (nth colls 3)) s4 (seq (nth colls 4)) res []] - (if (or (empty? s0) (empty? s1) (empty? s2) (empty? s3) (empty? s4)) - (apply list res) - (recur (rest s0) (rest s1) (rest s2) (rest s3) (rest s4) - (conj res (f (first s0) (first s1) (first s2) (first s3) (first s4)))))) - -(map str [1 2] [3 4] [5 6] [7 8] [9 0])`, + doc: `(assoc {[1] 2} [1] 3)`, extensions: [basicSetup, clojure()] }) @@ -202,7 +166,7 @@ function testExercisesUntilFail() { } testSolution(randExercise()) -//testSolution("powerset") +//testSolution("anagram") //loadExercise("go_counting") //testExercisesUntilFail() //testExercises() \ No newline at end of file diff --git a/scratch.clj b/scratch.clj index 076d4a7..6490433 100644 --- a/scratch.clj +++ b/scratch.clj @@ -447,4 +447,11 @@ (def colls [[7 8] [9 0]]) (def cs (conj colls c3 c2 c1)) -cs \ No newline at end of file +(def c ["meat" "mat" "team" "mate" "eat"]) + +(group-by frequencies c) + +{{\m 1, \e 1, \a 1, \t 1} + ["meat" "team" "mate"], + {\m 1, \a 1, \t 1} ["mat"], + {\e 1, \a 1, \t 1} ["eat"]} \ No newline at end of file diff --git a/src/clj/core.clj b/src/clj/core.clj index a359ac5..1babad8 100644 --- a/src/clj/core.clj +++ b/src/clj/core.clj @@ -784,9 +784,7 @@ (let* [mkns (namespace mk) mkn (name mk)] (cond (= mkn "keys") (assoc transforms mk (fn* [k] (keyword (or mkns (namespace k)) (name k)))) - (= mkn "syms") - (do (println "syms") - (assoc transforms mk (fn* [k] (list `quote (symbol (or mkns (namespace k)) (name k)))))) + (= mkn "syms") (assoc transforms mk (fn* [k] (list `quote (symbol (or mkns (namespace k)) (name k))))) (= mkn "strs") (assoc transforms mk str) :else transforms)) transforms)) diff --git a/src/clj/pprint.clj b/src/clj/pprint.clj index 50ce960..06bba82 100644 --- a/src/clj/pprint.clj +++ b/src/clj/pprint.clj @@ -36,6 +36,6 @@ (defn pprint [obj] (if (nil? obj) "nil" - (do (console-print obj) + (do ;(console-print obj) (cond (empty? obj) (str obj) :else (pp- obj 0))))) \ No newline at end of file diff --git a/src/core.js b/src/core.js index eaf0233..58a7602 100644 --- a/src/core.js +++ b/src/core.js @@ -130,7 +130,7 @@ function get(coll, key, notfound) { } } -function contains_Q(coll, key) { +export function contains_Q(coll, key) { if (coll === null) { return false } diff --git a/src/types.js b/src/types.js index 7dac24f..f449512 100644 --- a/src/types.js +++ b/src/types.js @@ -1,5 +1,6 @@ import { Fraction } from 'fraction.js' import { PRINT, READ } from './interpreter.js' +import {contains_Q} from './core.js' export function _obj_type(obj) { //console.log("[obj_type]", obj) @@ -396,14 +397,24 @@ export function _assoc_BANG(hm) { } return hm } - + var assoc_keys = new Set() + for (let i = 1; i < arguments.length; i += 2) { + assoc_keys.add(arguments[i]) + } + var new_map = new Map() + for (const [key, value] of hm) { + if (!contains_Q(assoc_keys, key)) { + new_map.set(key, value) + } + } for (var i = 1; i < arguments.length; i += 2) { var ktoken = arguments[i], vtoken = arguments[i + 1]; - hm.set(ktoken, vtoken) + new_map.set(ktoken, vtoken) } - return hm; + return new_map; } + export function _dissoc_BANG(hm) { for (var i = 1; i < arguments.length; i++) { var ktoken = arguments[i]; diff --git a/test/exercises.json b/test/exercises.json index f9c7349..b1382d1 100644 --- a/test/exercises.json +++ b/test/exercises.json @@ -152,7 +152,7 @@ "prime_factors" : "(defn least-prime-divisor\r\n [number]\r\n (or (first\r\n (filter #(zero? (rem number %1))\r\n (range 2 (inc (/ number 2)))))\r\n number))\r\n\r\n(defn of [number]\r\n (if\r\n (< number 2) []\r\n (let [divisor (least-prime-divisor number)]\r\n (into [divisor] (of (/ number divisor))))))\r\n", "triangle" : "(defn is-valid? [s1 s2 s3]\r\n (and\r\n (> s1 0) (> s2 0) (> s3 0)\r\n (>= (+ s1 s2) s3)\r\n (>= (+ s1 s3) s2)\r\n (>= (+ s2 s3) s1)))\r\n\r\n(defn equilateral? [s1 s2 s3]\r\n (and (is-valid? s1 s2 s3) (= s1 s2 s3)))\r\n\r\n(defn isosceles? [s1 s2 s3]\r\n (and (is-valid? s1 s2 s3) (or (= s1 s2) (= s1 s3) (= s2 s3))))\r\n\r\n(defn scalene? [s1 s2 s3]\r\n (and (not (isosceles? s1 s2 s3)) (is-valid? s1 s2 s3)))\r\n", "reverse_string" : "(ns reverse-string)\r\n\r\n(defn reverse-string [s] (apply str (reverse s)))\r\n", - "beer_song" : "(defn verse [n]\r\n (cond\r\n (= n 0) (str \"No more bottles of beer on the wall, no more bottles of beer.\\n\"\r\n \"Go to the store and buy some more, 99 bottles of beer on the wall.\\n\")\r\n (= n 1) (str \"1 bottle of beer on the wall, 1 bottle of beer.\\n\"\r\n \"Take it down and pass it around, no more bottles of beer on the wall.\\n\")\r\n (= n 2) (str \"2 bottles of beer on the wall, 2 bottles of beer.\\n\"\r\n \"Take one down and pass it around, 1 bottle of beer on the wall.\\n\")\r\n :else (str n \" bottles of beer on the wall, \" n \" bottles of beer.\\n\"\r\n \"Take one down and pass it around, \" (dec n) \" bottles of beer on the wall.\\n\")))\r\n\r\n(defn sing [start end]\r\n (if-not end (sing start 0)\r\n (->> (reverse (range end (inc start)))\r\n (map verse)\r\n (str/join \"\\n\"))))\r\n", + "beer_song" : "(defn verse [n]\r\n (cond\r\n (= n 0) (str \"No more bottles of beer on the wall, no more bottles of beer.\\n\"\r\n \"Go to the store and buy some more, 99 bottles of beer on the wall.\\n\")\r\n (= n 1) (str \"1 bottle of beer on the wall, 1 bottle of beer.\\n\"\r\n \"Take it down and pass it around, no more bottles of beer on the wall.\\n\")\r\n (= n 2) (str \"2 bottles of beer on the wall, 2 bottles of beer.\\n\"\r\n \"Take one down and pass it around, 1 bottle of beer on the wall.\\n\")\r\n :else (str n \" bottles of beer on the wall, \" n \" bottles of beer.\\n\"\r\n \"Take one down and pass it around, \" (dec n) \" bottles of beer on the wall.\\n\")))\r\n\r\n(defn sing\r\n ([start]\r\n (sing start 0))\r\n ([start end]\r\n (->> (reverse (range end (inc start)))\r\n (map verse)\r\n (str/join \"\n\"))))\r\n", "binary_search" : "(defn middle [alist]\r\n (-> alist (count) (quot 2)))\r\n\r\n(defn search-for\r\n [elem alist]\r\n (let [middle (middle alist)\r\n cur-elem (nth alist middle)]\r\n (cond\r\n (= cur-elem elem) middle\r\n (or (= middle (count alist)) (zero? middle)) (throw \"not found in list\")\r\n (< cur-elem elem) (+ middle (search-for elem (drop middle alist)))\r\n (> cur-elem elem) (search-for elem (take middle alist)))))\r\n", "clock" : "(defn clock [in-hour in-minute]\r\n (let [total-minutes (mod (+ (* in-hour 60) in-minute) (* 60 24))\r\n hours (mod (quot total-minutes 60) 24)\r\n minutes (mod total-minutes 60)]\r\n {:hour hours :minute minutes}))\r\n\r\n(defn fmt2 [n]\r\n (if (= (count (str n)) 1) (str 0 n) n))\r\n\r\n(defn clock->string [in-clock]\r\n (str (fmt2 (:hour in-clock)) \":\" (fmt2 (:minute in-clock))))\r\n\r\n(defn add-time [in-clock minutes-to-add]\r\n (clock (:hour in-clock) (+ (:minute in-clock) minutes-to-add)))\r\n", "allergies" : "(def allergens\r\n [:eggs :peanuts :shellfish :strawberries :tomatoes :chocolate :pollen :cats])\r\n\r\n(defn flagged?\r\n [flags index]\r\n (-> (bit-shift-right flags index)\r\n (bit-and 1)\r\n (pos?)))\r\n\r\n(defn allergies\r\n \"Given an 8-bit bitmap of flags, return the list of matching allergens.\"\r\n [flags]\r\n (keep-indexed (fn [index allergen]\r\n (when (flagged? flags index)\r\n allergen))\r\n allergens))\r\n\r\n(defn allergic-to?\r\n \"Given an 8-bit bitmap of flags and an allergen, return a boolean\r\n indicating whether or not the patient is allergic to the given allergen.\"\r\n [flags allergen]\r\n (some #{allergen} (allergies flags)))\r\n",