clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
simongray 2021-03-06T14:34:00.134Z

If I call (keys m) and (vals m) for the same m will the order of the keys match the order of the values?

dharrigan 2021-03-06T14:36:39.135Z

It does seem to imply that

dharrigan 2021-03-06T14:36:50.135200Z

user=> (doc keys)
-------------------------
clojure.core/keys
([map])
  Returns a sequence of the map's keys, in the same order as (seq map).
nil
user=> (doc vals)
-------------------------
clojure.core/vals
([map])
  Returns a sequence of the map's values, in the same order as (seq map).
nil

🙏 1
simongray 2021-03-06T14:37:06.135500Z

ah, stupid me, should have just looked at the docstring

simongray 2021-03-06T14:39:52.136900Z

my eyes were fixated on the source code which led me into some decompiled Java bytecode…

2021-03-06T14:40:10.137500Z

That is promised for the identical map objects. It is not promised for two different map objects for which clojure.core/= returns true.

simongray 2021-03-06T14:40:52.138300Z

good to know @andy.fingerhut, but thankfully it’s the same map instance

cassiel 2021-03-06T16:23:35.139300Z

If in doubt, you could just do a seq on the map which would deliver a list of [k, v] pairs which you could then split.

âž• 1
Yehonathan Sharvit 2021-03-06T18:41:41.140900Z

In “https://github.com/matthiasn/talk-transcripts/blob/master/Hickey_Rich/ClojureMadeSimple.md” Rich mentions the importance of “Loose coupling” Could someone explain what does he mean by “loose coupling” and how it applies in Clojure?

seancorfield 2021-03-06T18:48:09.141400Z

@viebel He talks more about it further into the preso: 40-50 mins in.

seancorfield 2021-03-06T18:48:24.141700Z

TL;DR: use generic, immutable data.

seancorfield 2021-03-06T18:49:13.142400Z

And nearly an hour in, he uses polymorphism a la carte as opposed to inheritance as another example for loose coupling.

2021-03-06T18:49:39.143Z

There are other basic examples I have heard, e.g. use queues to connect two parts of software, rather than having one make calls to the other by name to pass on pieces of work.

2021-03-06T18:50:07.143500Z

The ideas of loose vs. tight coupling are, I believe, fairly language independent, although the mechanisms for doing so can of course differ between languages.

2021-03-06T18:51:33.144Z

I suppose it would be accurate to say that loose coupling is more difficult to achieve in some programming languages than other.

Yehonathan Sharvit 2021-03-06T19:29:57.146500Z

@andy.fingerhut @seancorfield Would you agree with this example? In Clojure, a namespace that manipulates a map that represents customer data is loosely coupled with customer data. While in Java, a static method that manipulates a Customer record (or a immutable data class) is strongly coupled with Customer.

Yehonathan Sharvit 2021-03-06T19:31:23.147500Z

One benefit of Clojure approach is that the namespace doesn’t have to “import” the class definition for Customer

Yehonathan Sharvit 2021-03-06T19:32:17.148400Z

On the other hand, a Java developer might argue that the contract between code that manipulate Customer data and Customer data shape is not explicit

Yehonathan Sharvit 2021-03-06T19:33:46.149300Z

For instance, if you want to rename a field in Customer data, how would you discover all the pieced of code that need to be updated

Yehonathan Sharvit 2021-03-06T19:33:50.149500Z

?

Yehonathan Sharvit 2021-03-06T19:34:26.150200Z

> We should program the insides of our sytems like we progam the outsides

seancorfield 2021-03-06T19:35:24.151200Z

I think those are pretty reasonable claims. You could use Spec, if you really wanted to specify the fields that your function(s) required to be present.

Yehonathan Sharvit 2021-03-06T19:37:20.151600Z

When Rich gave his talk, there was no Spec

Yehonathan Sharvit 2021-03-06T19:37:47.152200Z

I think we should find answers to those objections without involving Spec

seancorfield 2021-03-06T19:39:04.153100Z

I suspect this discussion belongs in a different channel since it is more philosophical -- if you're comparing other languages -- than technical.

Yehonathan Sharvit 2021-03-06T19:39:35.153600Z

What channel? #data-oriented-programming maybe?

seancorfield 2021-03-06T19:41:09.154200Z

Sounds like a better place.

seancorfield 2021-03-06T19:41:19.154500Z

Then folks can opt-in if they wish.

borkdude 2021-03-06T19:44:12.154700Z

There is also #other-languages

Yehonathan Sharvit 2021-03-06T19:45:58.155100Z

Moved the discussion to #other-languages

1
2021-03-06T22:44:32.163300Z

Clauses are [accessor predicate & args] I need a structure that can store these clauses such that I can take an input value and get back a set of matching clauses, as in, If (apply (resolve predicate) (accessor input) args)is true, return the whole "clause"

(def clause-db
  '[[:a > 0]
    [:b < 5]
    [:c #{:a :b :c}]
    [:d = 22]])

(get-matching-clauses
  clause-db
  {:a 1
   :b 2
   :c :key})
;;=>
;;; returns matching clauses
#{[:a > 0]
  [:b < 5]
  [:c #{:a :b :c}]}
I want the get-matching-clauses function to be as efficient as possible, so for instance the same accessor shouldn't be called twice on the same input even if it is used in multiple clauses. I have a full working example/use case here: https://gist.github.com/jjttjj/ad9c6355d8b6741b43f23e90c7c77442 But I'm wondering if I'm reinventing some wheel. This is something like a rules engine however I don't need any working memory, inputs are only considered in isolation. And while the total number of relevant clauses will grow over time (by wrapping the clause db in an atom) only the set of clauses that exists when the input is compared is relevant. I just need function that can take a literal representation of some "matches", in a data structure that can be appended to, and an input, and check for the matches. Any thoughts on solutions to this?

Ben Sless 2021-03-07T14:25:52.220800Z

Sounds like a rule engine in reverse - the rules are the messages while the facts are the clauses

2021-03-07T20:18:33.242400Z

Hmm I'm starting to feel maybe https://github.com/noprompt/meander will be useful here but I haven't fully wrapped my head around it yet

Ben Sless 2021-03-08T14:53:02.251500Z

You can remove some dynamism from your solution, but otherwise it makes sense

(defprotocol IClause
  (-applies? [clause msg]))

(defrecord Clause0 [accessor f]
  IClause
  (-applies? [_ msg]
    (f (accessor msg))))

(defrecord Clause1 [accessor f a]
  IClause
  (-applies? [_ msg]
    (f (accessor msg) a)))

(def clause-db
  '[[:a > 0]
    [:b < 5]
    [:c #{:a :b :c}]
    [:d = 22]])

(defn compile-clause
  [[accessor f & args]]
  (let [accessor (if (symbol? accessor) (resolve accessor) accessor)]
    (case (count args)
      0 (->Clause0 accessor f)
      1 (apply ->Clause1 accessor f args))))

(def compiled-db
  (mapv compile-clause clause-db))

(defn apply-clauses
  [m]
  (into
   []
   (filter #(-applies? % m))
   compiled-db))

(apply-clauses
 {:a 1
  :b 2
  :c :key})

2021-03-08T15:18:50.260100Z

Thanks for this @ben.sless this looks good