This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-08-06
Channels
- # alda (3)
- # beginners (109)
- # boot (24)
- # cljsrn (17)
- # clojure (41)
- # clojure-brasil (2)
- # clojure-china (1)
- # clojure-russia (19)
- # clojure-spec (9)
- # clojure-uk (5)
- # clojurescript (44)
- # cloverage (5)
- # core-async (3)
- # css (2)
- # datascript (6)
- # datomic (26)
- # emacs (2)
- # events (10)
- # hoplon (24)
- # lambdaisland (1)
- # om (2)
- # onyx (16)
- # other-languages (10)
- # proto-repl (2)
- # re-frame (14)
- # spacemacs (2)
- # untangled (4)
- # videos (1)
(defn node-status [amx env & node-names]
(do-node-status amx env (or node-names (list-nodes amx env))))
How should I add an event listener while I’m writing reloading code?
hi, how do i work with 64 bit unsigned integers?
like, i have a few dumb questions about it 😛
if i do (bit-shift-left 1 63)
is that 1000000000000000000000000000000000000000000000000000000000000000
internally
and how do i see that binary representation as a string
i can’t quite get clojure.pprint/cl-format
to do what I want 😞
aaah i think i got it
I've been playing with implementing AVL trees in clojure and I wanted to write a property test to see if my balance is always within appropriate bounds after an insert. My avl tree is a nested map with :left and :right nodes. Is there a better way to do the collection of balance-factors than in this code I put together?
(defn balance-factors [avl-tree]
(let [factors (atom [])]
(w/postwalk (fn [thing]
(when (map? thing)
(swap! factors conj (balance-factor thing)))
thing) avl-tree)
@factors))
I got it to work through a (very) recursive process also, but this did seem to be an easier way to collect what I was looking for. Thoughts?
Trying to understand why `(defn task1 [ruleset inputs outputs ] (doseq [[left 😆 right] ruleset] (do(conj inputs left) (conj outputs right))) [inputs outputs])` returns me an empty vector
`(defn task1 [ruleset inputs outputs ] (doseq [[left 😆 right] ruleset] (do(conj inputs left) (conj outputs right))) [inputs outputs])`
After looking more at my problem, I realized if I generalized the in-order traversal function I already made to take a function, I could just pass it balance-factor and it'll collect everything I need.
(defn task1 [ruleset inputs outputs ]
(doseq [[left :-> right] ruleset] (do(conj inputs left)
(conj outputs right)))
[inputs outputs])
(def rule1 [[:a :b] :-> :c])
(def rule2 [[:c :d :e] :-> :f])
(def ruleset [rule1 rule2] )
One thing I see right away is that the
(do (conj inputs left)
(conj outputs right))
will only return the (conj outputs right)
due to clojure's immutability.For clojure's do, it does all the code in the block, then only returns the last result. Usually you'd use a do
block for side effects. conj doesn't cause any side-effects.
So this
(defn task1 [ruleset inputs outputs]
(let [[[inputs-a _-> outputs-a]
[inputs-b _-> outputs-b]] ruleset]
[(set (concat inputs-a inputs-b))
(set [outputs-a outputs-b])]))
Achieves the specific result you're asking for.It just uses clojure's built in destructuring to break apart the ruleset that you pass into the function.
the _-> is just a symbol that's standing in for the :->
. Underscores are what you'd generally use when you don't care about something in a destructure block, but you need to match on that 'place'
You can achieve what you're looking for by only destructuring the ruleset's one at a time with map.
Sorry, it's hard to explain. I put together this example using your code.
(require '[clojure.set :as set])
(defn task1 [rulesets]
(let [into-sets (map (fn [ruleset]
(let [[inputs _-> & outputs] ruleset]
[(set inputs)
(set outputs)])) rulesets)]
(reduce (fn [[accumulated-input
accumulated-output]
[new-input
new-output]]
[(set/union accumulated-input new-input)
(set/union accumulated-output new-output)])
into-sets)))
(def rule1 [[:a :b] :-> :c])
(def rule2 [[:c :d :e] :-> :f])
(def ruleset [rule1 rule2])
(task1 ruleset)
I broke up your task into 2 pieces. 1. Break out the inputs and outputs of each ruleset. 2. Combine these inputs and outputs using reduce. docs for map https://clojuredocs.org/clojure.core/map docs for reduce https://clojuredocs.org/clojure.core/reduce
Good luck! I hope you enjoy the process. Functional concepts are a bit of a mind-bend if you come from the OO, or imperative world.
@mjhamrick: would you mind explaining once again this piece:
[[inputs _-> & outputs] ruleset]
how does clojure think when it encounters the
[[:a :b] :-> :c]
and why the need for the &
That's clojure's destructuring at work. In some ways it's similar to pattern matching in other languages.
The &
is maybe not needed. It depends on how you consider outputs to be. In the case of clojure destructuring, an & will collect the rest of the values in a seq. By putting the & there, the outputs becomes a seq instead of a keyword. Since it's a seq, we can use the same pattern of (set my-seq)
. If we didn't use the &
, we would need to use another option such as (into #{} output)
or (#{output})
or (set [output])
.
Try typing this into your repl.
(let [[inputs _-> outputs] [[:input-a :input-b] :-> :output]]
(println inputs)
(println _->)
(println outputs))
(let [[inputs _-> & outputs] [[:input-a :input-b] :-> :output]]
(println inputs)
(println _->)
(println outputs))
I see, it treats it as a collection as if it were:
(let [[inputs _-> outputs] [[:input-a :input-b] :-> [:output-a :output-b]]]
(println inputs)
(println _->)
(println outputs))
[:input-a :input-b]
:->
[:output-a :output-b]
It's worth noting that one of the important ways that destructuring is different from Pattern matching is that destructuring blows up when you throw something at it that can't match at all.
I'm thinking of breaking up the rules into maps (instead of sets) where a key in a map would identify a particular rule and then the value would be what goes into the inputs
and outputs
sets now
Hi all,
(this is maybe an obvious concept but one that im failing to grasp)
why does clojure’s map return a list sequence
and not a vector in:
cljs.user=> (map #(+ 1 %) [1 2 3])
(2 3 4)
@dviramontes: I think it returns a sequence
map always returns a seq. If you want to return a vector (sometimes you do) you can either call vec on the result, or use mapv instead of map.
@senya22: thanks!
@mjhamrick: i know i can do (mapv #(+ 1 %) [1 2 3])
but returning a seq is by design no? what is that design ?
a transducer ? http://clojuredocs.org/clojure.core/map
> Returns a transducer when no collection is provided.
thats the part that confuses me..
I'm not sure on the exact reason, but I know one benefit of getting a lazy seq back from map is that you can do this.
(take 10 (map (partial + 1) (range))) ;; => (1 2 3 4 5 6 7 8 9 10)
(take 10 (mapv (partial + 1) (range))) ;; => runs forever
interesting..
@mjhamrick: trying to redefine your map-based rule parsing logic with
(defn map-rule-parser [rule]
(let [[inputs _-> & outputs] rule]
[(hash-map rule inputs)
(hash-map rule outputs)]))
(defn task1 [rulesets]
(let [into-sets (map map-rule-parser rulesets)]
;(println into-sets)
(reduce (fn [[accumulated-input
accumulated-output]
[new-input
new-output]]
[(set/union accumulated-input new-input)
(set/union accumulated-output new-output)])
into-sets)))
[{[[:a :b] :-> :c] [:a :b], [[:k :d :e] :-> :m] [:k :d :e], [[:c :d :e] :-> :f] [:c :d :e]}
{[[:a :b] :-> :c] (:c), [[:k :d :e] :-> :m] (:m), [[:c :d :e] :-> :f] (:f)}]
You probably want to replace set/union
with merge
or merge-with
(I can't remember which one)
@dviramontes: transducers give you a way of applying transformations to many other types of data structures, like streams, channels, strings (via StringBuilder), etc.
It looks like it is, but I think that's taking advantage of unspecified behavior of set/union. Since clojure sets are implemented as maps (citation needed) of value to value, union still works on them.
@mjhamrick: the behavior of set
operations on non-set data structures is undefined; I wouldn't recommend using them on other data structures
@mjhamrick: I'll look into the reducing behavior later, thanks
even if it works, it could potentially change in the future, and IIRC the set functions do unintuitive things to sequences
@mjhamrick: but is this the best way to key by the rule name:
(let [[inputs _-> & outputs] rule]
[(hash-map rule inputs)
(hash-map rule outputs)]
You can already use (get 'result-of-your-function-here' [[:a :b] :-> :c])
to get values out
yes. would it be better as a string or perhaps as a keyword, if I later want to use functions on that map to extract pieces
To turn into a string, you'll probably want to look into clojure.string/join
, and the str
function from core.
So as long as the keys are good in your domain, feel free to use any composite clojure value as the key.
Thanks for the explanation @mjhamrick !
@mjhamrick: would you mind explaining how that reducing function works once again please? Specifically, what are its parameters, also destructuring at work?
(defn set-rule-parser [rule]
(let [[inputs _-> & outputs] rule]
[(set inputs)
(set outputs)]))
(defn task1 [rulesets]
(let [into-sets (map set-rule-parser rulesets)]
(println "into-sets: " into-sets)
(reduce (fn [[accumulated-input
accumulated-output]
[new-input
new-output]]
[(set/union accumulated-input new-input)
(set/union accumulated-output new-output)])
into-sets)))
That reduce is a bit complicated since it's using quite a few features of clojure all at once. I'll try to break it down into the pieces.
(defn reduction [[accumulated-input
accumulated-output]
[new-input
new-output]]
[(set/union accumulated-input new-input)
(set/union accumulated-output new-output)])
=> #'user/reduction
(reduce reduction [#{:b :a} #{:c}] [#{:e :c :d} #{:f}] [#{:e :k :d} #{:m}])
ArityException Wrong number of args (4) passed to: core/reduce clojure.lang.AFn.throwArity (AFn.java:429)
;; The reduce is taking a function of 2 arguments. The first argument is the
;; collector, and the second argument is a single item.
;; The function to the reduce is taking advantage of the fact that Clojure lets
;; you destruct directly from the arguments vector.
(fn [[a b] [c d]]
;; do something
)
;; is basically equivalent to
(fn [a-and-b c-and-d]
(let [[a b] a-and-b
[c d] c-and-d]
;; do something
))
;; Keeping that in mind, we can see that the reducing function we're using is
;; breaking apart the accumulator and the current item. We're accumulating with
;; input and output as separate sets or maps. Each item that's passed in is also
;; a vector of 2 items. The input and the output from a single function. This
;; came in through mapping the set-rule-parser. So each input to the reduction
;; function is a into-sets item.
I was trying to reproduce it given that into-sets: ([#{:b :a} #{:c}] [#{:e :c :d} #{:f}] [#{:e :k :d} #{:m}])
, but getting that ArityException
(reduce reduction (seq [#{:b :a} #{:c}] [#{:e :c :d} #{:f}] [#{:e :k :d} #{:m}])) ArityException Wrong number of args (3) passed to: core/seq--4128 clojure.lang.AFn.throwArity (AFn.java:429)
Oh I see what the issue was. You're giving 4 things to reduce where it's expecting one collection (in this case of the 4 things)
(reduce reduction [[#{:b :a} #{:c}] [#{:e :c :d} #{:f}] [#{:e :k :d} #{:m}]])
slight change. Just added brackets
hm, I attempted this before, thought it was the same thing:
ArityException Wrong number of args (2) passed to: PersistentVector clojure.lang.AFn.throwArity (AFn.java:429)
(reduce reduction (seq [#{:b :a} #{:c}] [#{:e :c :d} #{:f}] [#{:e :k :d} #{:m}]))
sorry:
(reduce reduction (seq [#{:b :a} #{:c}] [#{:e :c :d} #{:f}] [#{:e :k :d} #{:m}]))
ArityException Wrong number of args (3) passed to: core/seq--4128 clojure.lang.AFn.throwArity (AFn.java:429)
So, in a reducing function, is it always the case that the first arg is an accumulator and a second is a current value? Would that be a correct assumption? And then you simply taking advantage of a fact that every incoming item is a composition of 2 things: inputs & output
In a general reducing function you are right. Accumulator is the first value, and the second is a value from the collection you are reducing over.
One small 'catch' of reduce, is that if you don't give it an initialization value, it will take the first two items from your collection. In this example, it takes 1 to be the accumulator and 2 to be the item from the collection. These are the arguments to +, and then the result (3) is the new accumulator for the next value (3).
This continues
acc = 1 -> 3 -> 6 -> 10
itm = 2 -> 3 -> 4
where there are no items left, reduce returns the accumulator.