I'm trying to solve this SICP exercise using clojure with core/match and core/typed.
I'm kind of following Jeanine Adkisson's "Variants are Not Unions" talk.
This is what I got so far:
(ns sicp.chapter2_ex29
(:require [clojure.core.typed :as t]
[clojure.core.match :refer [match]]))
; Type definitions
(t/defalias Mobile '{:left Branch, :right Branch})
(t/defalias Weight Number)
(t/defalias Structure
(t/U '[(t/Value :weight) Weight]
'[(t/Value :mobile) Mobile]))
(t/defalias Branch '{:length Number, :structure Structure})
; Constructors
(t/ann make-mobile [Branch Branch -> Mobile])
(defn make-mobile [left right]
{:left left :right right})
(t/ann make-branch [Number Structure -> Branch])
(defn make-branch [length structure]
{:length length :structure structure})
; Getters
(t/ann left-branch [Mobile -> Branch])
(defn left-branch [mobile]
(:left mobile))
(t/ann right-branch [Mobile -> Branch])
(defn right-branch [mobile]
(:right mobile))
(t/ann branch-length [Branch -> Number])
(defn branch-length [branch]
(:length branch))
(t/ann branch-structure [Branch -> Structure])
(defn branch-structure [branch]
(:structure branch))
; Total weight
(t/ann total-weight [Mobile -> Number])
(defn total-weight [mobile]
(t/letfn> [structure-weight :- [Structure -> Number]
(structure-weight [structure]
(do
(println (str "structure -> " structure))
(println (str "structure0 -> " (get structure 0)))
(println (str "structure1 -> " (get structure 1)))
(match structure
[:weight weight] weight
[:mobile mobile] (total-weight mobile))))
branch-weight :- [Branch -> Number]
(branch-weight [branch]
(structure-weight (branch-structure branch)))]
(let
[left (branch-weight (left-branch mobile))
right (branch-weight (right-branch mobile))]
(do
(println (str "left ->" left))
(println (str "right ->" right))
(+ left right)))))
(t/ann mobile1 Mobile)
(def mobile1 (make-mobile
(make-branch 3 [:weight 4])
(make-branch 5 [:weight 2])))
(total-weight mobile1) ; <- works as expected = 6
(t/ann mobile2 Mobile)
(def mobile2 (make-mobile
(make-branch 3 [:weight 4])
(make-branch 5 [:mobile (make-mobile
(make-branch 2 [:weight 3])
(make-branch 4 [:weight 2]))])))
(total-weight mobile2) ; <- throws java.lang.IllegalArgumentException: No matching clause: [:mobile {:left {:length 2, :structure [:weight 3]}, :right {:length 4, :structure [:weight 2]}}]
The Structure type is a variant: either it is a weight, which is simply a number (it has the form [:weight weight] where weight is a Number) or it is a mobile (it has the form [:mobile mobile] where mobile is something of type Mobile).
It type-checks and the total-weight function works for a simple input: a Mobile made of two Weights.
But as you can see it fails for a Mobile with a Branch that is a Mobile.
For some reason it isn't matching the [:mobile mobile] case. Any idea on what am I doing wrong?
The problem appears to be that the identifier mobile in
(match structure
[:weight weight] weight
[:mobile mobile] (total-weight mobile))))
... is already bound as an argument in the enclosing function definition:
(defn total-weight [mobile]
... )
Changing the match form to
(match structure
[:weight w] w
[:mobile m] (total-weight m))))
... removes the error.
The rule appears to be:
If a name in a match pattern is bound, it is not rebound locally. It
is interpreted as its prevailing value.
I have to say I only found the error by accident. I would prefer that the local binding took precedence, but it doesn't.
Notes
The syntax of your match expression does not follow the documentation, which would require ...
(match [structure]
[[:weight w]] w
[[:mobile m]] (total-weight m))
... but your abbreviated version works just as well.
The Clojure idiom is to use standard data structures - especially maps - where possible, eschewing access functions and constructors. In this way, we can write something like
; Total weight
(declare structure-weight)
(t/ann total-weight [Mobile -> Number])
(defn total-weight [mobile]
(match [mobile]
[{:left bl, :right br}]
(apply + (map
(comp structure-weight :structure)
[bl br]))))
(t/ann structure-weight [Structure -> Number])
(defn structure-weight [structure]
(match [structure]
[[:weight w]] w
[[:mobile m]] (total-weight m)))
Related
I am trying to use Instaparse to make a simple arithmetic expression evaluator. The parser seems to work fine but I cannot figure out how to evaluate the returned nested vector. Currently I am using postwalk, like this
(ns test5.core
(:require [instaparse.core :as insta])
(:require [clojure.walk :refer [postwalk]])
(:gen-class))
(def WS
(insta/parser
"WS = #'\\s+'"))
(def transform-options
{:IntLiteral read-string})
(def parser
(insta/parser
"AddExpr = AddExpr '+' MultExpr
| AddExpr '-' MultExpr
| MultExpr
MultExpr = MultExpr '*' IntLiteral
| MultExpr '/' IntLiteral
| IntLiteral
IntLiteral = #'[0-9]+'"
:auto-whitespace WS))
(defn parse[input]
(->> (parser input)
(insta/transform transform-options)))
(defn visit [node]
(println node)
(cond
(number? node) node
(string? node) (resolve (symbol node))
(vector? node)
(cond
(= :MultExpr (first node)) (visit (rest node))
(= :AddExpr (first node)) (visit (rest node))
:else node)
:else node))
(defn evaluate [tree]
(println tree)
(postwalk visit tree))
(defn -main
[& args]
(evaluate (parse "1 * 2 + 3")))
postwalk does traverse the vector but I get a nested list as the result, eg
((((1) #'clojure.core/* 2)) #'clojure.core/+ (3))
Use org.clojure/core.match. Base on your current grammar, you can write the evaluation function as:
(defn eval-expr [expr]
(match expr
[:MultExpr e1 "*" e2] (* (eval-expr e1)
(eval-expr e2))
[:MultExpr e1 "/" e2] (/ (eval-expr e1)
(eval-expr e2))
[:AddExpr e1 "+" e2] (+ (eval-expr e1)
(eval-expr e2))
[:AddExpr e1 "-" e2] (- (eval-expr e1)
(eval-expr e2))
[:MultExpr e1] (eval-expr e1)
[:AddExpr e1] (eval-expr e1)
:else expr))
and evaluate with:
(-> "1 * 2 + 3"
parse
eval-expr)
;; => 5
This doesn't use Instaparse or clojure.walk, but here's something I had for evaluating infix math using only reduce:
(defn evaluate
"Evaluates an infix arithmetic form e.g. (1 + 1 * 2)."
[e]
(let [eval-op (fn [op a b]
(let [f (resolve op)]
(f a b)))]
(reduce
(fn [[v op] elem]
(cond
(coll? elem)
(if op
[(eval-op op v (first (evaluate elem))) nil]
[(first (evaluate elem)) nil])
(and op (number? elem))
[(eval-op op v elem) nil]
(number? elem)
[elem nil]
(symbol? elem)
[v elem]
:else
(throw (ex-info "Invalid evaluation" {:v v :op op :elem (type elem)}))))
[0 nil]
e)))
(first (evaluate (clojure.edn/read-string "(1 * 2 + 3)")))
=> 5
(first (evaluate (clojure.edn/read-string "(1 * 2 + (3 * 5))")))
=> 17
This requires the input string to represent a valid Clojure list. I also had this function for grouping multiplication/division:
(defn pemdas
"Groups division/multiplication operations in e into lists."
[e]
(loop [out []
rem e]
(if (empty? rem)
(seq out)
(let [curr (first rem)
next' (second rem)]
(if (contains? #{'/ '*} next')
(recur (conj out (list curr next' (nth rem 2)))
(drop 3 rem))
(recur (conj out curr) (rest rem)))))))
(pemdas '(9.87 + 4 / 3 * 0.41))
=> (9.87 + (4 / 3) * 0.41)
This exact problem is why I first created the Tupelo Forest library.
Please see the talk from Clojure Conj 2017.
I've started some docs here. You can also see live examples here.
Update
Here is how you could use the Tupelo Forest library to do it:
First, define your Abstract Syntax Tree (AST) data using Hiccup format:
(with-forest (new-forest)
(let [data-hiccup [:rpc
[:fn {:type :+}
[:value 2]
[:value 3]]]
root-hid (add-tree-hiccup data-hiccup)
with result:
(hid->bush root-hid) =>
[{:tag :rpc}
[{:type :+, :tag :fn}
[{:tag :value, :value 2}]
[{:tag :value, :value 3}]]]
Show how walk-tree works using a "display interceptor"
disp-interceptor {:leave (fn [path]
(let [curr-hid (xlast path)
curr-node (hid->node curr-hid)]
(spyx curr-node)))}
>> (do
(println "Display walk-tree processing:")
(walk-tree root-hid disp-interceptor))
with result:
Display walk-tree processing:
curr-node => {:tupelo.forest/khids [], :tag :value, :value 2}
curr-node => {:tupelo.forest/khids [], :tag :value, :value 3}
curr-node => {:tupelo.forest/khids [1037 1038], :type :+, :tag :fn}
curr-node => {:tupelo.forest/khids [1039], :tag :rpc}
then define the operators and an interceptor to transform a subtree like (+ 2 3) => 5
op->fn {:+ +
:* *}
math-interceptor {:leave (fn [path]
(let [curr-hid (xlast path)
curr-node (hid->node curr-hid)
curr-tag (grab :tag curr-node)]
(when (= :fn curr-tag)
(let [curr-op (grab :type curr-node)
curr-fn (grab curr-op op->fn)
kid-hids (hid->kids curr-hid)
kid-values (mapv hid->value kid-hids)
result-val (apply curr-fn kid-values)]
(set-node curr-hid {:tag :value :value result-val} [])))))}
] ; end of let form
; imperative step replaces old nodes with result of math op
(walk-tree root-hid math-interceptor)
We can then display the modified AST tree which contains the result of (+ 2 3):
(hid->bush root-hid) =>
[{:tag :rpc}
[{:tag :value, :value 5}]]
You can see the live code here.
I was trying to modify a vector of vector but ended up with lazy-seq inside. I am new to clojure. Can someone help me to get this correctly?
(require '[clojure.string :as str])
;;READ CUST.TXT
(def my_str(slurp "cust.txt"))
(defn esplit [x] (str/split x #"\|" ))
(def cust (vec (sort-by first (vec (map esplit (vec (str/split my_str #"\n")))))))
;;func to print
(for [i cust] (do (println (str (subs (str i) 2 3) ": [" (subs (str i) 5 (count (str i)))))))
;;CODE TO SEARCH CUST
(defn cust_find [x] (for [i cust :when (= (first i) x )] (do (nth i 1))))
(type (cust_find "2"))
;;READ PROD.TXT
(def my_str(slurp "prod.txt"))
(def prod (vec (sort-by first (vec (map esplit (vec (str/split my_str #"\n")))))))
;;func to print
(for [i prod] (do (println (str (subs (str i) 2 3) ": [" (subs (str i) 5 (count (str i)))))))
;;CODE TO SEARCH PROD
(defn prod_find [x y] (for [i prod :when (= (first i) x )] (nth i y)))
(prod_find "2" 1)
(def my_str(slurp "sales.txt"))
(def sales (vec (sort-by first (vec (map esplit (vec (str/split my_str #"\n")))))))
; (for [i (range(count sales))] (cust_find (nth (nth sales i) 1)))
; (defn fill_sales_1 [x]
; (assoc x 1
; (cust_find (nth x 1))))
; (def sales(map fill_sales_1 (sales)))
(def sales (vec (for [i (range(count sales))] (assoc (nth sales i) 1 (str (cust_find (nth (nth sales i) 1)))))))
; (for [i (range(count sales))] (assoc (nth sales i) 2 (str (prod_find (nth (nth sales i) 2) 1))))
(for [i sales] (println i))
When I print sales vector I get
[1 clojure.lang.LazySeq#10ae5ccd 1 3]
[2 clojure.lang.LazySeq#a5d0ddf9 2 3]
[3 clojure.lang.LazySeq#a5d0ddf9 1 1]
[4 clojure.lang.LazySeq#d80cb028 3 4]
If you need the text files I will upload them as well.
In Clojure, for and map, as well as other functions and macros working with sequences, generate a lazy sequence instead of a vector.
In the REPL, lazy sequences are usually fully computed when printing - to have it printed, it's enough to remove the str in your second to last line:
(def sales (vec (for [i (range(count sales))] (assoc (nth sales i) 1 (cust_find (nth (nth sales i) 1))))))
Just in case, note that your code can be prettified / simplified to convey the meaning better. For example, you are just iterating over a sequence of sales - you don't need to iterate over the indices and then get each item using nth:
(def sales
(vec (for [rec sales])
(assoc rec 1 (cust_find (nth rec 1)))))
Second, you can replace nth ... 1 with second - it will be easier to understand:
(def sales
(vec (for [rec sales])
(assoc rec 1 (cust_find (second rec))))
Or, alternatively, you can just use update instead of assoc:
(def sales
(vec (for [rec sales])
(update rec 1 cust_find)))
And, do you really need the outer vec here? You can do most of what you intend without it:
(def sales
(for [rec sales])
(update rec 1 cust_find))
Also, using underscores in Clojure function names is considered bad style: dashes (as in cust-find instead of cust_find) are easier to read and easier to type.
(for [i sales] (println (doall i)))
doall realizes a lazy sequence. Bare in mind that if the sequence is huge, you might not want to do this.
I am working with SICP and exercise 2.29-b gave me the opportunity to have fun with the Continuation Passing Style while traversing mobiles and branches.
To make the story short, each mobile has left and right branch, which are composed by a length and either a numeric weight or another mobile. The question asks to find the total weight given a mobile.
After the first mutually recursive solution, quite simple, I tried and successfully implemented a cps' one:
(defn total-weight-cps [mobile]
(letfn
[(branch-weight-cps
[branch kont]
(let [structure (branch-structure branch)]
(if (mobile? (branch-structure branch))
(do (println "then " structure) (kont (traverse-mobile-cps structure identity)))
(do (println "else " structure) (kont structure)))))
(traverse-mobile-cps
[mobile kont]
(branch-weight-cps (left-branch mobile)
(fn [left-weight]
(branch-weight-cps (right-branch mobile)
(fn [right-weight] (kont (+ left-weight right-weight)))))))]
(traverse-mobile-cps mobile identity)))
At this point, I have tried to apply the trampoline in order to preserve my stack. But it blows with the following exception:
java.lang.ClassCastException: sicp_clojure.2_1_exercises_2_24_2_32$total_weight_STAR_$traverse_mobile_cps__6694$fn__6695$fn__6696$fn__6697 cannot be cast to java.lang.Number
Numbers.java:126 clojure.lang.Numbers.add
.../git/sicp-clojure/src/sicp_clojure/2_1_exercises_2_24_2_32.clj:185 sicp-clojure.2-1-exercises-2-24-2-32/total-weight*[fn]
core.clj:5801 clojure.core/trampoline
core.clj:5806 clojure.core/trampoline
RestFn.java:439 clojure.lang.RestFn.invoke
.../git/sicp-clojure/src/sicp_clojure/2_1_exercises_2_24_2_32.clj:186 sicp-clojure.2-1-exercises-2-24-2-32/total-weight*
The code using trampoline, following the excellent link, is:
(defn total-weight* [mobile]
(letfn
[(branch-weight-cps
[branch kont]
(let [structure (branch-structure branch)]
(if (mobile? (branch-structure branch))
(do (println "then " structure) (kont (traverse-mobile-cps structure identity)))
(do (println "else " structure) (kont structure)))))
(traverse-mobile-cps
[mobile kont]
(branch-weight-cps (left-branch mobile)
(fn [left-weight]
(branch-weight-cps (right-branch mobile)
(fn [right-weight] #(kont (+ left-weight right-weight)))))))]
(trampoline traverse-mobile-cps mobile identity)))
And finally some sample data:
(def branch11 (make-branch 1 1))
(def branch22 (make-branch 2 2))
(def branch36 (make-branch 3 6))
(def branch43 (make-branch 4 3))
(def mobile11-43 (make-mobile branch11 branch43))
(def mobile36-22 (make-mobile branch36 branch22))
(def branch5m1143 (make-branch 5 mobile11-43))
(def branch7m3622 (make-branch 7 mobile36-22))
(def mobile5m1143-7m3622 (make-mobile branch5m1143 branch7m3622))
(total-weight* mobile5m1143-7m3622)
Why does it blow up?
Following the same link in my post, I have solved turning my implementation in:
(defn total-weight* [mobile]
(letfn
[(branch-weight-cps
[branch kont]
(let [structure (branch-structure branch)]
(if (mobile? (branch-structure branch))
(fn [] (traverse-mobile-cps structure kont))
(fn [] (kont structure)))))
(traverse-mobile-cps
[mobile kont]
(branch-weight-cps (left-branch mobile)
(fn [left-weight]
(branch-weight-cps (right-branch mobile)
(fn [right-weight] #(kont (+ left-weight right-weight)))))))]
(trampoline traverse-mobile-cps mobile identity)))
as I mentioned earlier that I'm working on poker hands in clojure, I'm on its final stages of completion. I'm just having problem in its winning-hand function, which should be like it returns the hand from a list of hands that is the highest, but if there are ties, then it should return the list of all of those hands.
So, here is my winning-hand function:
(defn hand-rank
"Return a value indicating how high the hand ranks."
[hand]
(let [ranks (card-ranks hand)]
(cond
(and (straight ranks) (u-flush hand)) (-> [] (conj 8) (conj (apply max ranks)))
(kind 4 ranks) (-> [] (conj 7) (conj (kind 4 ranks)) (conj (kind 1 ranks)))
(and (kind 3 ranks) (kind 2 ranks)) (-> [] (conj 6) (conj (kind 3 ranks)) (conj (kind 2 ranks)))
(u-flush hand) (-> [] (conj 5) (conj ranks))
(straight ranks) (conj [4] (apply max ranks))
(kind 3 ranks) (-> [3] (conj (kind 3 ranks)) (conj ranks))
(two-pair ranks) (-> [2] (conj (two-pair ranks)) (conj ranks))
(kind 2 ranks) (-> [1] (conj (kind 2 ranks)) (conj ranks))
:else (-> [0] (conj ranks))
)))
(defn winning-hand
"Return the max hand of the given poker hands."
[hands]
(let [min-count (count (apply min-key count (for [hand hands]
(hand-rank hand))))]
(reduce (fn [x y]
(if (<= 0 (compare (subvec (vec (flatten (hand-rank x))) 0 min-count)
(subvec (vec (flatten (hand-rank y))) 0 min-count)))
x
y)) hands)))
(defn allmax
"Return a list of all items equals to the max of the sequence."
[coll]
(let [maximum (winning-hand coll)]
(for [x coll :when (= maximum x)]
x)))
(defn winning-list
"Return a list of winning hands. poker([hand1, hand2, ...] => [hand, ..."
[hands]
(allmax hands))
The winning-list function works fine when there is no tie, but in case of tie, it is still returning only one hand and not a list of all the hands that are highest. For e.g.: In this case ["AC", "2C", "3C", "4C", "5C"] '["AH", "2H", "3H", "4H", "5H"] '["AD", "2D", "3D", "4D", "5D"] '["AC", "2S", "3H", "4D", "5H"]), it should return '["AC", "2C", "3C", "4C", "5C"] '["AH", "2H", "3H", "4H", "5H"] '["AD", "2D", "3D", "4D", "5D"]. Could someone tell me what I'm doing wrong?
You are testing equality on the hand itself, not it's "value" (IE straight flush 1 through 5). You want something like this.
(defn allmax
"Return a list of all items equals to the max of the sequence."
[coll]
(let [maximum (winning-hand coll)]
(for [x coll :when (= (hand-value maximum) (hand-value x)]
x)))
An even better solution would probably have you implement a comparator for the hands and use that here and in other places.
What's the problem with following code:
the func expression get expression that contains term that can contain expression...
(defn term[]
(def mytmp (zip/xml-zip {:tag :term}))
(cond
(= (first(:content(first vecTok))) "(")
(do
(def mytmp (popVecTo mytmp))
(def mytmp (zip/append-child mytmp (expression)))
(def mytmp (popVecTo mytmp)))
:else
(def mytmp (popVecTo mytmp)))
(zip/node mytmp))
(defn expression[]
(def mytmp (zip/xml-zip {:tag :expression}))
(def mytmp (zip/append-child mytmp (term)))
(while (contains? #{"+", "-", "*","/", "&", "|", "<", ">", "="} (first(:content(first vecTok))) )
(do
(def mytmp (popVecTo mytmp))
(def mytmp (zip/append-child mytmp (term)))))
(zip/node mytmp))
(def vecTok (vec (:content(first(xml-seq (parse "C:/Users/User/Desktop/forHekronot/BallT.xml"))))))
In the file :
<a><symbol>(</symbol><identifier>dy</identifier><symbol>-</symbol><identifier>dx</identifier><symbol>)</symbol></a>
Notwithstanding #jszakmeister's comment on how to better solve the problem, let me try to give and answer to the question:
you can first (def expression) and then (defn term [] ...) and finally (defn expression [] ...).
The classic example for indirect recursion is of course the poor man's odd/even function for positive numbers:
clojurec.core=> (def even)
#'clojurec.core/even
clojurec.core=> (defn odd [x] (and (not (= x 0)) (even (dec x))))
#'clojurec.core/odd
clojurec.core=> (defn even [x] (or (= x 0) (odd (dec x))))
#'clojurec.core/even
clojurec.core=> (even 10)
true
clojurec.core=> (odd 10)
false
clojurec.core=> (odd 10000)
StackOverflowError clojure.lang.Numbers.equal (Numbers.java:214)
Ooops, depending on the size (or rather depth) of your file this could be a problem. But not all is lost, we can redefine even to use trampoline internally:
(defn even [n]
(letfn [(evenrec [x] (or (= x 0) #(oddrec (dec x))))
(oddrec [x] (and (not (= x 0)) #(evenrec (dec x))))]
(trampoline evenrec n)))