From 59201a507454cf6c9e875e6907158284d6427e5c Mon Sep 17 00:00:00 2001 From: Bobbi Towers Date: Tue, 5 Sep 2023 19:09:25 -0700 Subject: [PATCH 1/6] rename `fn` to `fn*` --- main.js | 4 +- src/clj/core.clj | 93 ++++++++++++++++++++++++++-------------------- src/interpreter.js | 2 +- 3 files changed, 55 insertions(+), 44 deletions(-) diff --git a/main.js b/main.js index d9d4d43..0971d7f 100644 --- a/main.js +++ b/main.js @@ -165,8 +165,8 @@ function testExercisesUntilFail() { console.log("Fails:", fails) } -testSolution(randExercise()) -//testSolution("binary") +//testSolution(randExercise()) +testSolution("binary") //loadExercise("all_your_base") //testExercisesUntilFail() //testExercises() \ No newline at end of file diff --git a/src/clj/core.clj b/src/clj/core.clj index 6cd2183..1183532 100644 --- a/src/clj/core.clj +++ b/src/clj/core.clj @@ -1,34 +1,33 @@ -(ns core {:clj-kondo/ignore true} - (:require [clojure.string :as str])) +(ns core {:clj-kondo/ignore true}) (defmacro defn [name & fdecl] (if (string? (first fdecl)) (if (list? (second fdecl)) - `(def ~name (with-meta (fn ~@(rest fdecl)) + `(def ~name (with-meta (fn* ~@(rest fdecl)) ~{:name (str name) :doc (first fdecl)})) - `(def ~name (with-meta (fn ~(second fdecl) (do ~@(nnext fdecl))) + `(def ~name (with-meta (fn* ~(second fdecl) (do ~@(nnext fdecl))) ~{:name (str name) :doc (first fdecl)}))) (if (list? (first fdecl)) - `(def ~name (with-meta (fn ~@fdecl) + `(def ~name (with-meta (fn* ~@fdecl) ~{:name (str name)})) - `(def ~name (with-meta (fn ~(first fdecl) (do ~@(rest fdecl))) + `(def ~name (with-meta (fn* ~(first fdecl) (do ~@(rest fdecl))) ~{:name (str name)}))))) (defmacro defn- [name & fdecl] (if (string? (first fdecl)) (if (list? (second fdecl)) - `(def ~name (with-meta (fn ~@(rest fdecl)) + `(def ~name (with-meta (fn* ~@(rest fdecl)) ~{:name (str name) :doc (first fdecl)})) - `(def ~name (with-meta (fn ~(second fdecl) (do ~@(nnext fdecl))) + `(def ~name (with-meta (fn* ~(second fdecl) (do ~@(nnext fdecl))) ~{:name (str name) :doc (first fdecl)}))) (if (list? (first fdecl)) - `(def ~name (with-meta (fn ~@fdecl) + `(def ~name (with-meta (fn* ~@fdecl) ~{:name (str name)})) - `(def ~name (with-meta (fn ~(first fdecl) (do ~@(rest fdecl))) + `(def ~name (with-meta (fn* ~(first fdecl) (do ~@(rest fdecl))) ~{:name (str name)}))))) (defmacro lazy-seq [& body] - `(new LazySeq (fn [] ~@body))) + `(new LazySeq (fn* [] ~@body))) (defn not [a] (if a false true)) (defn not= [a b] (not (= a b))) @@ -87,12 +86,12 @@ (defn merge-with [f & maps] (when (some identity maps) - (let [merge-entry (fn [m e] + (let [merge-entry (fn* [m e] (let [k (key e) v (val e)] (if (contains? m k) (assoc m k (f (get m k) v)) (assoc m k v)))) - merge2 (fn [m1 m2] + merge2 (fn* [m1 m2] (reduce merge-entry (or m1 {}) (seq m2)))] (reduce merge2 maps)))) @@ -133,21 +132,21 @@ (defn juxt ([f] - (fn + (fn* ([] [(f)]) ([x] [(f x)]) ([x y] [(f x y)]) ([x y z] [(f x y z)]) ([x y z & args] [(apply f x y z args)]))) ([f g] - (fn + (fn* ([] [(f) (g)]) ([x] [(f x) (g x)]) ([x y] [(f x y) (g x y)]) ([x y z] [(f x y z) (g x y z)]) ([x y z & args] [(apply f x y z args) (apply g x y z args)]))) ([f g h] - (fn + (fn* ([] [(f) (g) (h)]) ([x] [(f x) (g x) (h x)]) ([x y] [(f x y) (g x y) (h x y)]) @@ -155,7 +154,7 @@ ([x y z & args] [(apply f x y z args) (apply g x y z args) (apply h x y z args)]))) ([f g h & fs] (let [fs (list* f g h fs)] - (fn + (fn* ([] (reduce #(conj %1 (%2)) [] fs)) ([x] (reduce #(conj %1 (%2 x)) [] fs)) ([x y] (reduce #(conj %1 (%2 x y)) [] fs)) @@ -166,7 +165,7 @@ ([] identity) ([f] f) ([f g] - (fn + (fn* ([] (f (g))) ([x] (f (g x))) ([x y] (f (g x y))) @@ -203,7 +202,7 @@ (defn memoize [f] (let* [mem (atom {})] - (fn [& args] + (fn* [& args] (let* [key (str args)] (if (contains? @mem key) (get @mem key) @@ -212,7 +211,7 @@ ret))))))) (defn partial [pfn & args] - (fn [& args-inner] + (fn* [& args-inner] (apply pfn (concat args args-inner)))) (defn every? [pred xs] @@ -227,14 +226,14 @@ (walk (partial prewalk f) identity (f form))) (defn postwalk-replace [smap form] - (postwalk (fn [x] (if (contains? smap x) (smap x) x)) form)) + (postwalk (fn* [x] (if (contains? smap x) (smap x) x)) form)) (defn apply-template [argv expr values] (postwalk-replace (zipmap argv values) expr)) (defmacro do-template [argv expr & values] (let [c (count argv)] - `(do ~@(map (fn [a] (apply-template argv expr a)) + `(do ~@(map (fn* [a] (apply-template argv expr a)) (partition c values))))) (defmacro are [argv expr & args] @@ -315,7 +314,7 @@ (not (zero? (mod n 2)))) (defn complement [f] - (fn + (fn* ([] (not (f))) ([x] (not (f x))) ([x y] (not (f x y))) @@ -331,7 +330,7 @@ (remove nil? (cons node (when (branch? node) - (mapcat (fn [x] (tree-seq branch? children x)) + (mapcat (fn* [x] (tree-seq branch? children x)) (children node)))))) (defn flatten [x] @@ -395,15 +394,15 @@ (defn partition-by [f coll] (loop [s (seq coll) res []] (if (= 0 (count s)) res - (recur (drop (count (take-while (fn [x] (= (f (first s)) (f x))) s)) s) - (conj res (take-while (fn [x] (= (f (first s)) (f x))) s)))))) + (recur (drop (count (take-while (fn* [x] (= (f (first s)) (f x))) s)) s) + (conj res (take-while (fn* [x] (= (f (first s)) (f x))) s)))))) (defn coll? [x] (or (list? x) (vector? x) (set? x) (map? x))) (defn group-by [f coll] (reduce - (fn [ret x] + (fn* [ret x] (let* [k (f x)] (assoc ret k (conj (get ret k []) x)))) {} coll)) @@ -500,7 +499,7 @@ (defn drop-last [n coll] (if-not coll (drop-last 1 n) - (map (fn [x _] x) coll (drop n coll)))) + (map (fn* [x _] x) coll (drop n coll)))) (defn interleave [c1 c2] (loop [s1 (seq c1) @@ -530,11 +529,11 @@ ~else))))) (defn frequencies [coll] - (reduce (fn [counts x] + (reduce (fn* [counts x] (assoc counts x (inc (get counts x 0)))) {} coll)) -(defn constantly [x] (fn [& args] x)) +(defn constantly [x] (fn* [& args] x)) (defn str/capitalize [s] (let* [s (str s)] @@ -552,7 +551,7 @@ (defn not-empty [coll] (when (seq coll) coll)) (defn reduce-kv [f init coll] - (reduce (fn [ret kv] (f ret (first kv) (last kv))) init coll)) + (reduce (fn* [ret kv] (f ret (first kv) (last kv))) init coll)) (defn merge [& maps] (loop [maps (mapcat seq maps) res {}] @@ -663,8 +662,8 @@ (defmacro for [seq-exprs body-expr] (let [body-expr* body-expr iter# (gensym) - to-groups (fn [seq-exprs] - (reduce (fn [groups kv] + to-groups (fn* [seq-exprs] + (reduce (fn* [groups kv] (if (keyword? (first kv)) (conj (pop groups) (conj (peek groups) [(first kv) (last kv)])) (conj groups [(first kv) (last kv)]))) @@ -746,27 +745,27 @@ defaults (:or b)] (loop [ret (-> bvec (conj gmap) (conj v) (conj gmap) (conj gmap) - ((fn [ret] + ((fn* [ret] (if (:as b) (conj ret (:as b) gmap) ret)))) bes (let* [transforms (reduce - (fn [transforms mk] + (fn* [transforms mk] (if (keyword? mk) (let* [mkns (namespace mk) mkn (name mk)] - (cond (= mkn "keys") (assoc transforms mk (fn [k] (keyword (or mkns (namespace k)) (name k)))) + (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)))))) + (assoc transforms mk (fn* [k] (list `quote (symbol (or mkns (namespace k)) (name k)))))) (= mkn "strs") (assoc transforms mk str) :else transforms)) transforms)) {} (keys b))] (reduce - (fn [bes entry] (reduce (fn [a b] (assoc a b ((val entry) b))) (dissoc bes (key entry)) (get bes (key entry)))) + (fn* [bes entry] (reduce (fn* [a b] (assoc a b ((val entry) b))) (dissoc bes (key entry)) (get bes (key entry)))) (dissoc b :as :or) transforms))] bes @@ -795,14 +794,14 @@ (defn destructure [bindings] (let* [bents (partition 2 bindings) - process-entry (fn [bvec b] (pb bvec (first b) (second b)))] + process-entry (fn* [bvec b] (pb bvec (first b) (second b)))] (if (every? symbol? (map first bents)) bindings (if-let [kwbs (seq (filter #(keyword? (first %)) bents))] (throw (str "Unsupported binding key: " (ffirst kwbs))) (reduce process-entry [] bents))))) -#_(defn maybe-destructured [params body] +(defn maybe-destructured [params body] (if (every? symbol? params) (cons params body) (loop [params params @@ -819,7 +818,7 @@ ~@body)))))) ;redefine fn with destructuring -#_(defmacro fn [& sigs] +(defmacro fn [& sigs] (let [name (if (symbol? (first sigs)) (first sigs) nil) sigs (if name (next sigs) sigs) sigs (if (vector? (first sigs)) @@ -832,6 +831,7 @@ (first sigs) " should be a vector") (str "Parameter declaration missing"))))) + _ (println sigs) psig (fn* [sig] ;; Ensure correct type before destructuring sig (when (not (seq? sig)) @@ -869,6 +869,17 @@ (cons 'fn* new-sigs)) (meta &form)))) +#_(fn ([[exponent bit]] + (if (= "1" bit) + (Math/pow 2 exponent) + 0))) + +#_((fn ([[exponent bit]] + (if (= "1" bit) + (Math/pow 2 exponent) + 0))) + [0 "1"]) + (defmacro let [bindings & body] `(let* ~(destructure bindings) ~@body)) diff --git a/src/interpreter.js b/src/interpreter.js index ae2d340..4e7a16d 100644 --- a/src/interpreter.js +++ b/src/interpreter.js @@ -213,7 +213,7 @@ function _EVAL(ast, env) { ast = a2; } break; - case "fn": + case "fn*": //console.log("[eval fn] defining fn", PRINT(ast)) if (types._list_Q(a1)) { return types.multifn(EVAL, Env, ast.slice(1), env); From 719c207ceaab5e1783bb317c4d706b4077dccb0b Mon Sep 17 00:00:00 2001 From: Bobbi Towers Date: Tue, 5 Sep 2023 19:40:24 -0700 Subject: [PATCH 2/6] appears to work --- main.js | 8 ++++-- src/clj/core.clj | 64 +++++++++--------------------------------------- src/types.js | 3 +++ 3 files changed, 20 insertions(+), 55 deletions(-) diff --git a/main.js b/main.js index 0971d7f..aaa7a32 100644 --- a/main.js +++ b/main.js @@ -7,7 +7,11 @@ import testSuites from './test/tests.json'; import { evalString, deftests, clearTests } from "./src/interpreter" let editorState = EditorState.create({ - doc: `(map-indexed #(when (= 2 %2) [%1 "Hi"]) [1 1 2 2])`, + doc: `((fn ([[exponent bit]] + (if (= "1" bit) + (Math/pow 2 exponent) + 0))) + [0 "1"])`, extensions: [basicSetup, clojure()] }) @@ -166,7 +170,7 @@ function testExercisesUntilFail() { } //testSolution(randExercise()) -testSolution("binary") +//testSolution("binary") //loadExercise("all_your_base") //testExercisesUntilFail() //testExercises() \ No newline at end of file diff --git a/src/clj/core.clj b/src/clj/core.clj index 1183532..84f094c 100644 --- a/src/clj/core.clj +++ b/src/clj/core.clj @@ -801,6 +801,9 @@ (throw (str "Unsupported binding key: " (ffirst kwbs))) (reduce process-entry [] bents))))) +(defmacro let [bindings & body] + `(let* ~(destructure bindings) ~@body)) + (defn maybe-destructured [params body] (if (every? symbol? params) (cons params body) @@ -825,68 +828,23 @@ (list sigs) (if (seq? (first sigs)) sigs - ;; Assume single arity syntax (throw (if (seq sigs) (str "Parameter declaration " (first sigs) " should be a vector") (str "Parameter declaration missing"))))) - _ (println sigs) psig (fn* [sig] - ;; Ensure correct type before destructuring sig - (when (not (seq? sig)) - (throw (str "Invalid signature " sig - " should be a list"))) - (let [[params & body] sig - _ (when (not (vector? params)) - (throw (if (seq? (first sigs)) - (str "Parameter declaration " params - " should be a vector") - (str "Invalid signature " sig - " should be a list")))) - conds (when (and (next body) (map? (first body))) - (first body)) - body (if conds (next body) body) - conds (or conds (meta params)) - pre (:pre conds) - post (:post conds) - body (if post - `((let [~'% ~(if (< 1 (count body)) - `(do ~@body) - (first body))] - ~@(map (fn* [c] `(assert ~c)) post) - ~'%)) - body) - body (if pre - (concat (map (fn* [c] `(assert ~c)) pre) - body) - body)] + (let [[params & body] sig] (maybe-destructured params body))) new-sigs (map psig sigs)] - (with-meta - (if name - (list* 'fn* name new-sigs) - (cons 'fn* new-sigs)) - (meta &form)))) - -#_(fn ([[exponent bit]] - (if (= "1" bit) - (Math/pow 2 exponent) - 0))) - -#_((fn ([[exponent bit]] - (if (= "1" bit) - (Math/pow 2 exponent) - 0))) - [0 "1"]) - -(defmacro let [bindings & body] - `(let* ~(destructure bindings) ~@body)) + (if name + (list* 'fn* name new-sigs) + (cons 'fn* new-sigs)))) (defmacro condp [pred expr & clauses] (let [gpred (gensym "pred__") gexpr (gensym "expr__") - emit (defn emit [pred expr args] + emit-condp (defn emit-condp [pred expr args] (let [[[a b c :as clause] more] (split-at (if (= :>> (second args)) 3 2) args) n (count clause)] @@ -895,13 +853,13 @@ (= 1 n) a (= 2 n) `(if (~pred ~a ~expr) ~b - ~(emit pred expr more)) + ~(emit-condp pred expr more)) :else `(if-let [p# (~pred ~a ~expr)] (~c p#) - ~(emit pred expr more)))))] + ~(emit-condp pred expr more)))))] `(let [~gpred ~pred ~gexpr ~expr] - ~(emit gpred gexpr clauses)))) + ~(emit-condp gpred gexpr clauses)))) (defn Math/log [n] (js-eval (str "Math.log(" n ")"))) diff --git a/src/types.js b/src/types.js index 036e2d0..c0f156a 100644 --- a/src/types.js +++ b/src/types.js @@ -217,6 +217,9 @@ export function _regex_Q(obj) { export function walk(inner, outer, form) { //console.log("Walking form:", form) + if (typeof form === 'undefined') { + return null + } if (_list_Q(form)) { return outer(form.map(inner)) } else if (form === null) { From 713c4d18a1de8f64b5cd319f12e2cd94fb5d37de Mon Sep 17 00:00:00 2001 From: Bobbi Towers Date: Tue, 5 Sep 2023 19:56:22 -0700 Subject: [PATCH 3/6] first define let, fn without destructuring --- src/clj/core.clj | 137 ++++++++++++++++++++++++++------------------- src/interpreter.js | 2 +- 2 files changed, 81 insertions(+), 58 deletions(-) diff --git a/src/clj/core.clj b/src/clj/core.clj index 84f094c..c329ae9 100644 --- a/src/clj/core.clj +++ b/src/clj/core.clj @@ -1,29 +1,98 @@ (ns core {:clj-kondo/ignore true}) +(defmacro when [x & xs] (list 'if x (cons 'do xs))) + +(defmacro cond [& xs] + (when (> (count xs) 0) + (list 'if (first xs) + (if (> (count xs) 1) + (nth xs 1) + (throw "odd number of forms to cond")) + (cons 'cond (rest (rest xs)))))) + +(def map1 (fn* [f coll] + (loop [s (seq coll) res []] + (if (empty? s) res + (recur (rest s) + (conj res (if (keyword? f) (get (first s) f) (f (first s))))))))) + +(def map2 (fn* [f c1 c2] + (loop [s1 (seq c1) s2 (seq c2) res []] + (if (or (empty? s1) (empty? s2)) res + (recur (rest s1) (rest s2) + (conj res (f (first s1) (first s2)))))))) + +(def map3 (fn* [f c1 c2 c3] + (loop [s1 (seq c1) s2 (seq c2) s3 (seq c3) res []] + (if (or (empty? s1) (empty? s2) (empty? s3)) res + (recur (rest s1) (rest s2) (rest s3) + (conj res (f (first s1) (first s2) (first s3)))))))) + +(def map4 (fn* [f c1 c2 c3 c4] + (loop [s1 (seq c1) s2 (seq c2) s3 (seq c3) s4 (seq c4) res []] + (if (or (empty? s1) (empty? s2) (empty? s3) (empty? s4)) res + (recur (rest s1) (rest s2) (rest s3) (rest s4) + (conj res (f (first s1) (first s2) (first s3) (first s4)))))))) + +(def map (fn* [f & colls] + (cond + (empty? (first colls)) '() + (= 1 (count colls)) (map1 f (first colls)) + (= 2 (count colls)) (map2 f (first colls) (second colls)) + (= 3 (count colls)) (map3 f (first colls) (second colls) (last colls)) + (= 4 (count colls)) (map4 f (first colls) (second colls) (nth colls 2) (last colls)) + :else (throw (str "Map not implemented on " (count colls) " colls"))))) + +(def seq? (fn* [x] (list? x))) + +;; first define let, fn without destructuring + +(defmacro let [bindings & body] + `(let* ~bindings ~@body)) + +(defmacro fn [& sigs] + (let [name (if (symbol? (first sigs)) (first sigs) nil) + sigs (if name (next sigs) sigs) + sigs (if (vector? (first sigs)) + (list sigs) + (if (seq? (first sigs)) + sigs + (throw (if (seq sigs) + (str "Parameter declaration " + (first sigs) + " should be a vector") + (str "Parameter declaration missing"))))) + psig (fn* [sig] + sig) + new-sigs (map psig sigs)] + (if name + (list* 'fn* name new-sigs) + (cons 'fn* new-sigs)))) + (defmacro defn [name & fdecl] (if (string? (first fdecl)) (if (list? (second fdecl)) - `(def ~name (with-meta (fn* ~@(rest fdecl)) + `(def ~name (with-meta (fn ~@(rest fdecl)) ~{:name (str name) :doc (first fdecl)})) - `(def ~name (with-meta (fn* ~(second fdecl) (do ~@(nnext fdecl))) + `(def ~name (with-meta (fn ~(second fdecl) (do ~@(nnext fdecl))) ~{:name (str name) :doc (first fdecl)}))) (if (list? (first fdecl)) - `(def ~name (with-meta (fn* ~@fdecl) + `(def ~name (with-meta (fn ~@fdecl) ~{:name (str name)})) - `(def ~name (with-meta (fn* ~(first fdecl) (do ~@(rest fdecl))) + `(def ~name (with-meta (fn ~(first fdecl) (do ~@(rest fdecl))) ~{:name (str name)}))))) (defmacro defn- [name & fdecl] (if (string? (first fdecl)) (if (list? (second fdecl)) - `(def ~name (with-meta (fn* ~@(rest fdecl)) + `(def ~name (with-meta (fn ~@(rest fdecl)) ~{:name (str name) :doc (first fdecl)})) - `(def ~name (with-meta (fn* ~(second fdecl) (do ~@(nnext fdecl))) + `(def ~name (with-meta (fn ~(second fdecl) (do ~@(nnext fdecl))) ~{:name (str name) :doc (first fdecl)}))) (if (list? (first fdecl)) - `(def ~name (with-meta (fn* ~@fdecl) + `(def ~name (with-meta (fn ~@fdecl) ~{:name (str name)})) - `(def ~name (with-meta (fn* ~(first fdecl) (do ~@(rest fdecl))) + `(def ~name (with-meta (fn ~(first fdecl) (do ~@(rest fdecl))) ~{:name (str name)}))))) (defmacro lazy-seq [& body] @@ -35,14 +104,6 @@ (defn zero? [n] (= 0 n)) (defn identity [x] x) -(defmacro cond [& xs] - (when (> (count xs) 0) - (list 'if (first xs) - (if (> (count xs) 1) - (nth xs 1) - (throw "odd number of forms to cond")) - (cons 'cond (rest (rest xs)))))) - (defn next [s] (if (or (= 1 (count s)) (= 0 (count s))) nil @@ -196,9 +257,9 @@ (def gensym-counter (atom 0)) -(defn gensym [prefix] - (symbol (str (if prefix prefix "G__") - (swap! gensym-counter inc)))) +(def gensym (fn* [prefix] + (symbol (str (if prefix prefix "G__") + (swap! gensym-counter inc))))) (defn memoize [f] (let* [mem (atom {})] @@ -250,8 +311,6 @@ (defn not-every? [pred xs] (not (every? pred xs))) -(defmacro when [x & xs] (list 'if x (cons 'do xs))) - (defmacro if-not [test then else] `(if (not ~test) ~then ~else)) @@ -454,39 +513,6 @@ (map? coll) {} (string? coll) "")) -(defn map1 [f coll] - (loop [s (seq coll) res []] - (if (empty? s) res - (recur (rest s) - (conj res (if (keyword? f) (get (first s) f) (f (first s)))))))) - -(defn map2 [f c1 c2] - (loop [s1 (seq c1) s2 (seq c2) res []] - (if (or (empty? s1) (empty? s2)) res - (recur (rest s1) (rest s2) - (conj res (f (first s1) (first s2))))))) - -(defn map3 [f c1 c2 c3] - (loop [s1 (seq c1) s2 (seq c2) s3 (seq c3) res []] - (if (or (empty? s1) (empty? s2) (empty? s3)) res - (recur (rest s1) (rest s2) (rest s3) - (conj res (f (first s1) (first s2) (first s3))))))) - -(defn map4 [f c1 c2 c3 c4] - (loop [s1 (seq c1) s2 (seq c2) s3 (seq c3) s4 (seq c4) res []] - (if (or (empty? s1) (empty? s2) (empty? s3) (empty? s4)) res - (recur (rest s1) (rest s2) (rest s3) (rest s4) - (conj res (f (first s1) (first s2) (first s3) (first s4))))))) - -(defn map [f & colls] - (cond - (empty? (first colls)) '() - (= 1 (count colls)) (map1 f (first colls)) - (= 2 (count colls)) (map2 f (first colls) (second colls)) - (= 3 (count colls)) (map3 f (first colls) (second colls) (last colls)) - (= 4 (count colls)) (map4 f (first colls) (second colls) (nth colls 2) (last colls)) - :else (throw (str "Map not implemented on " (count colls) " colls")))) - (defn mapv [f & colls] (cond (empty? (first colls)) '() @@ -542,9 +568,6 @@ (str (upper-case (subs s 0 1)) (lower-case (subs s 1)))))) -(defn seq? [x] - (list? x)) - (defn keep [s] (remove nil? s)) diff --git a/src/interpreter.js b/src/interpreter.js index 4e7a16d..a06d73b 100644 --- a/src/interpreter.js +++ b/src/interpreter.js @@ -84,7 +84,7 @@ export var deftests = [] function _EVAL(ast, env) { while (true) { - //console.log(ast) + //console.log(PRINT(ast)) //console.log(env) if (!types._list_Q(ast)) { return eval_ast(ast, env); From f18301b26c74a18a9e15a53e2beb06d5bcadf9f5 Mon Sep 17 00:00:00 2001 From: Bobbi Towers Date: Tue, 5 Sep 2023 20:18:04 -0700 Subject: [PATCH 4/6] fix two-fer exercise, because arities matter now --- main.js | 2 +- test/exercises.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/main.js b/main.js index aaa7a32..6f9a72e 100644 --- a/main.js +++ b/main.js @@ -170,7 +170,7 @@ function testExercisesUntilFail() { } //testSolution(randExercise()) -//testSolution("binary") +testSolution("two_fer") //loadExercise("all_your_base") //testExercisesUntilFail() //testExercises() \ No newline at end of file diff --git a/test/exercises.json b/test/exercises.json index cc96f07..583386b 100644 --- a/test/exercises.json +++ b/test/exercises.json @@ -124,7 +124,7 @@ "atbash_cipher" : "(def letters\r\n (map char\r\n (range (int \"A\") (inc (int \"z\")))))\r\n\r\n(def to-cipher\r\n (apply hash-map\r\n (interleave letters (reverse letters))))\r\n\r\n(defn sanitize\r\n [plaintext]\r\n (str/replace (str/lower-case plaintext) #\"\\\\W\" \"\"))\r\n\r\n(defn cipher\r\n [plain-char]\r\n (or (to-cipher plain-char) plain-char))\r\n\r\n(defn to-chunks\r\n [character-list]\r\n (map #(apply str %) (partition 5 5 character-list)))\r\n\r\n(defn encode\r\n [plaintext]\r\n (->> plaintext\r\n sanitize\r\n (map cipher)\r\n to-chunks\r\n (str/join \" \")))\r\n", "grade_school" : "(defn add [db name grade]\r\n (merge-with concat db (hash-map grade [name])))\r\n\r\n(defn grade [db grade]\r\n (get db grade []))\r\n\r\n(defn sorted [db]\r\n (->> db\r\n (map (fn [k-v] [(first k-v) (sort (last k-v))]))\r\n (into (sorted-map))\r\n (sort)))\r\n", "meetup" : "(def day-structure\r\n {1 :sunday 2 :monday 3 :tuesday 4 :wednesday\r\n 5 :thursday 6 :friday 7 :saturday})\r\n\r\n(defn leap-year? [year]\r\n (cond (zero? (mod year 400)) true\r\n (zero? (mod year 100)) false\r\n :else (zero? (mod year 4))))\r\n\r\n(defn zellers-congruence [input_year input_month input_day]\r\n (let [month (+ (mod (+ input_month 9) 12) 3)\r\n year (- input_year (quot (- month input_month) 12))\r\n century (quot year 100)\r\n century-year (mod year 100)]\r\n (mod (+ input_day\r\n (quot (* 26 (inc month)) 10)\r\n century-year\r\n (quot century-year 4)\r\n (quot century 4)\r\n (* 5 century)) 7)))\r\n\r\n(defn get-day-counts [year]\r\n {1 31, 2 (if (leap-year? year) 29 28), 3 31, 4 30\r\n 5 31, 6 30, 7 31, 8 31, 9 30, 10 31, 11 30, 12 31})\r\n\r\n(defn get-days\r\n ([year month]\r\n (get-days year month\r\n (zellers-congruence year month 1)\r\n (get-in (get-day-counts year) [month])))\r\n ([year month start-day limit]\r\n (loop [count 2\r\n day (inc start-day)\r\n day-arrangement {1 (get-in day-structure [start-day])}]\r\n (if (not= count (inc limit))\r\n (recur (inc count)\r\n (if (= (inc day) 8) 1 (inc day))\r\n (assoc day-arrangement count\r\n (get-in day-structure [day])))\r\n day-arrangement))))\r\n\r\n(defn filter-by-day [year month day]\r\n (let [days (get-days year month)]\r\n (apply hash-map (flatten (filter #(-> % val (= day)) days)))))\r\n\r\n(defn filter-keys [year month day style]\r\n (let [days (filter-by-day year month day)\r\n dates (sort (keys days))]\r\n (cond\r\n (= style :first)\r\n (nth dates 0)\r\n (= style :second)\r\n (nth dates 1)\r\n (= style :third)\r\n (nth dates 2)\r\n (= style :fourth)\r\n (nth dates 3)\r\n (= style :last)\r\n (nth dates (dec (count dates)))\r\n (= style :teenth)\r\n (first (filter #(and (> % 12) (< % 20)) (vec dates))))))\r\n\r\n(defn meetup [month year day style]\r\n [year month (filter-keys year month day style)])", - "two_fer" : "(defn two-fer [name]\r\n (if name\r\n (str \"One for \" name \", one for me.\")\r\n \"One for you, one for me.\"))\r\n", + "two_fer" : "(defn two-fer\r\n ([] \"One for you, one for me.\")\r\n ([name]\r\n (str \"One for \" name \", one for me.\")\r\n \"One for you, one for me.\"))\r\n", "run_length_encoding" : "(defn encoder-groups [string]\r\n (re-seq #\"(.)\\\\1*\" string))\r\n\r\n(defn encoder-values [group]\r\n (str (if (> (count group) 1)\r\n (count group)\r\n \"\")\r\n (first group)))\r\n\r\n(defn run-length-encode [s]\r\n (let [groups (re-seq #\"(.)\\\\1*\" s)]\r\n (apply str\r\n (map encoder-values groups))))\r\n\r\n(defn decoder-groups [string]\r\n (re-seq #\"(\\\\d+)?(.)\" string))\r\n\r\n(defn decoder-values [group]\r\n (apply str (repeat (Integer/parseInt (first (re-seq #\"\\\\d+\" group))) \r\n (last group))))\r\n\r\n(defn run-length-decode [s]\r\n (let [groups (re-seq #\"(\\\\d+)?(.)\" s)]\r\n (apply str\r\n (map decoder-values groups))))\r\n", "wordy" : "(def ops {\"plus\" +\r\n \"minus\" -\r\n \"multiplied by\" *\r\n \"divided by\" /})\r\n\r\n(def tokens-pattern (re-pattern\r\n (str (join \"|\" (keys ops)) \"|-?\\\\d+|\\\\S+\")))\r\n\r\n(defn parse-op [op-str]\r\n (or (ops op-str)\r\n (throw (str \"unknown operator \" op-str))))\r\n\r\n(defn evaluate [expr]\r\n (if-let [[_ exprs] (re-matches #\"What is (.+)\\?\" expr)]\r\n (if-let [[token & tokens] (re-seq tokens-pattern exprs)]\r\n (reduce (fn [acc [op x]]\r\n ((parse-op op) acc (Integer/parseInt x)))\r\n (Integer/parseInt token) (partition-all 2 tokens))\r\n (throw \"no arithmetic expression found\"))\r\n (throw \"cannot recognize question\")))\r\n", "sieve" : "(defn prime? [n]\r\n (->> n\r\n Math/sqrt\r\n Math/floor\r\n inc\r\n (range 2)\r\n (filter #(zero? (rem n %)))\r\n empty?))\r\n(defn sieve [n]\r\n (->> n\r\n inc\r\n (range 2)\r\n (filter prime?)))\r\n", From 751122ae0edca6f1a33bfa916df97567b4014d65 Mon Sep 17 00:00:00 2001 From: Bobbi Towers Date: Tue, 5 Sep 2023 20:33:59 -0700 Subject: [PATCH 5/6] define map as single multiarity fn --- main.js | 2 +- src/clj/core.clj | 118 ++++++++++++++++++++--------------------------- 2 files changed, 52 insertions(+), 68 deletions(-) diff --git a/main.js b/main.js index 6f9a72e..6b3c382 100644 --- a/main.js +++ b/main.js @@ -170,7 +170,7 @@ function testExercisesUntilFail() { } //testSolution(randExercise()) -testSolution("two_fer") +//testSolution("two_fer") //loadExercise("all_your_base") //testExercisesUntilFail() //testExercises() \ No newline at end of file diff --git a/src/clj/core.clj b/src/clj/core.clj index c329ae9..c0c4e9b 100644 --- a/src/clj/core.clj +++ b/src/clj/core.clj @@ -10,38 +10,56 @@ (throw "odd number of forms to cond")) (cons 'cond (rest (rest xs)))))) -(def map1 (fn* [f coll] - (loop [s (seq coll) res []] - (if (empty? s) res - (recur (rest s) - (conj res (if (keyword? f) (get (first s) f) (f (first s))))))))) - -(def map2 (fn* [f c1 c2] - (loop [s1 (seq c1) s2 (seq c2) res []] - (if (or (empty? s1) (empty? s2)) res - (recur (rest s1) (rest s2) - (conj res (f (first s1) (first s2)))))))) - -(def map3 (fn* [f c1 c2 c3] - (loop [s1 (seq c1) s2 (seq c2) s3 (seq c3) res []] - (if (or (empty? s1) (empty? s2) (empty? s3)) res - (recur (rest s1) (rest s2) (rest s3) - (conj res (f (first s1) (first s2) (first s3)))))))) - -(def map4 (fn* [f c1 c2 c3 c4] - (loop [s1 (seq c1) s2 (seq c2) s3 (seq c3) s4 (seq c4) res []] - (if (or (empty? s1) (empty? s2) (empty? s3) (empty? s4)) res - (recur (rest s1) (rest s2) (rest s3) (rest s4) - (conj res (f (first s1) (first s2) (first s3) (first s4)))))))) - -(def map (fn* [f & colls] - (cond - (empty? (first colls)) '() - (= 1 (count colls)) (map1 f (first colls)) - (= 2 (count colls)) (map2 f (first colls) (second colls)) - (= 3 (count colls)) (map3 f (first colls) (second colls) (last colls)) - (= 4 (count colls)) (map4 f (first colls) (second colls) (nth colls 2) (last colls)) - :else (throw (str "Map not implemented on " (count colls) " colls"))))) +(def spread (fn* [arglist] + (cond + (nil? arglist) nil + (nil? (next arglist)) (seq (first arglist)) + :else (cons (first arglist) (spread (next arglist)))))) + +(def list* (fn* + ([args] (seq args)) + ([a args] (cons a args)) + ([a b args] (cons a (cons b args))) + ([a b c args] (cons a (cons b (cons c args)))) + ([a b c d & more] + (cons a (cons b (cons c (cons d (spread more)))))))) + +(def apply (fn* + ([f args] + (if (keyword? f) + (get args f) + (apply* f args))) + ([f x args] + (apply f (list* x args))) + ([f x y args] + (apply f (list* x y args))) + ([f x y z args] + (apply f (list* x y z args))) + ([f a b c d & args] + (apply f (cons a (cons b (cons c (cons d (spread args))))))))) + +(def map + (fn* + ([f coll] + (loop [s (seq coll) res []] + (if (empty? s) (apply list res) + (recur (rest s) + (conj res (if (keyword? f) (get (first s) f) (f (first s)))))))) + ([f c1 c2] + (loop [s1 (seq c1) s2 (seq c2) res []] + (if (or (empty? s1) (empty? s2)) res + (recur (rest s1) (rest s2) + (conj res (f (first s1) (first s2))))))) + ([f c1 c2 c3] + (loop [s1 (seq c1) s2 (seq c2) s3 (seq c3) res []] + (if (or (empty? s1) (empty? s2) (empty? s3)) res + (recur (rest s1) (rest s2) (rest s3) + (conj res (f (first s1) (first s2) (first s3))))))) + ([f c1 c2 c3 c4] + (loop [s1 (seq c1) s2 (seq c2) s3 (seq c3) s4 (seq c4) res []] + (if (or (empty? s1) (empty? s2) (empty? s3) (empty? s4)) res + (recur (rest s1) (rest s2) (rest s3) (rest s4) + (conj res (f (first s1) (first s2) (first s3) (first s4))))))))) (def seq? (fn* [x] (list? x))) @@ -163,34 +181,6 @@ (recur (inc index) (str buffer (get cmap (nth s index) (nth s index))))))) -(defn apply - ([f args] - (if (keyword? f) - (get args f) - (apply* f args))) - ([f x args] - (apply f (list* x args))) - ([f x y args] - (apply f (list* x y args))) - ([f x y z args] - (apply f (list* x y z args))) - ([f a b c d & args] - (apply f (cons a (cons b (cons c (cons d (spread args)))))))) - -(defn spread [arglist] - (cond - (nil? arglist) nil - (nil? (next arglist)) (seq (first arglist)) - :else (cons (first arglist) (spread (next arglist))))) - -(defn list* - ([args] (seq args)) - ([a args] (cons a args)) - ([a b args] (cons a (cons b args))) - ([a b c args] (cons a (cons b (cons c args)))) - ([a b c d & more] - (cons a (cons b (cons c (cons d (spread more))))))) - (defn juxt ([f] (fn* @@ -514,13 +504,7 @@ (string? coll) "")) (defn mapv [f & colls] - (cond - (empty? (first colls)) '() - (= 1 (count colls)) (map1 f (first colls)) - (= 2 (count colls)) (map2 f (first colls) (second colls)) - (= 3 (count colls)) (map3 f (first colls) (second colls) (last colls)) - (= 4 (count colls)) (map4 f (first colls) (second colls) (nth colls 2) (last colls)) - :else (throw (str "Map not implemented on " (count colls) " colls")))) + (vec (map f (spread colls)))) (defn drop-last [n coll] (if-not coll From f53b5a538f7f8f59ec8fdda8f542fd5ff1e73362 Mon Sep 17 00:00:00 2001 From: Bobbi Towers Date: Tue, 5 Sep 2023 20:36:22 -0700 Subject: [PATCH 6/6] all map arities return lists --- src/clj/core.clj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/clj/core.clj b/src/clj/core.clj index c0c4e9b..072f3fd 100644 --- a/src/clj/core.clj +++ b/src/clj/core.clj @@ -47,17 +47,17 @@ (conj res (if (keyword? f) (get (first s) f) (f (first s)))))))) ([f c1 c2] (loop [s1 (seq c1) s2 (seq c2) res []] - (if (or (empty? s1) (empty? s2)) res + (if (or (empty? s1) (empty? s2)) (apply list res) (recur (rest s1) (rest s2) (conj res (f (first s1) (first s2))))))) ([f c1 c2 c3] (loop [s1 (seq c1) s2 (seq c2) s3 (seq c3) res []] - (if (or (empty? s1) (empty? s2) (empty? s3)) res + (if (or (empty? s1) (empty? s2) (empty? s3)) (apply list res) (recur (rest s1) (rest s2) (rest s3) (conj res (f (first s1) (first s2) (first s3))))))) ([f c1 c2 c3 c4] (loop [s1 (seq c1) s2 (seq c2) s3 (seq c3) s4 (seq c4) res []] - (if (or (empty? s1) (empty? s2) (empty? s3) (empty? s4)) res + (if (or (empty? s1) (empty? s2) (empty? s3) (empty? s4)) (apply list res) (recur (rest s1) (rest s2) (rest s3) (rest s4) (conj res (f (first s1) (first s2) (first s3) (first s4)))))))))