Fork me on GitHub
#clojure
<
2018-11-25
>
todo03:11:45

@cfleming: I have an external tool similar to the IntelliJ Todo "applet" -- it collects comments matching a certain regex, and when you click on the comment, it jumps the IDE to the corresponding file/line

kari.marttila10:11:24

Clojure gurus! I'd like to have a short comment to one design decision. I have three various environments which all connect to their data sources a bit differently and also the data processing is a bit different. I need to implement n different functions for data processing. I could do this using multimethods and dispatch based on environmental variable value which I know for each environment (defined in profiles.clj). But I was wondering if this could be implemented more elegantly e.g. using protocols. Any suggestions?

kari.marttila10:11:46

I was reading about protocols in "Joy of Clojure" and "Clojure Applied". I think I have an idea how to do it more elegantly. I create one namespace per one environment/defrecord definition, and inside that defrecord I define the data processing functions for that environment. I'll create a git branch for this and experiment a bit. Clojure is so fun. πŸ™‚

kari.marttila13:11:48

Damn, I love Clojure REPL. And using IntelliJ IDEA with Cursive and its REPL makes experimenting with the code so fluent and fast. I was having major difficulties to figure out how to call function b from function a using the same protocol. Then I experimented it using REPL and figured out how to do it in a couple of minutes just by experimenting.

jaihindh.reddy13:11:34

"You're living in your program invoking your tools, instead of living in your tools invoking your program" - Stuart Halloway.

kari.marttila13:11:12

But... I have one issue I can't figure out how to do and the Clojure books I have doesn't provide an example for that.

jaihindh.reddy13:11:40

And what would that be?

kari.marttila13:11:59

(defprotocol EmailProtocol (lowername [this name]) (email [this host])) (defrecord EmailRecord [ourcompany] EmailProtocol (lowername [this name] (clojure.string/lower-case name)) (email [this contractor] (let [contractorname (lowername this contractor) companyname (lowername this ourcompany)] (str "ext-" contractorname "@" companyname))))

kari.marttila13:11:21

This works well when EmailProtocol and EmailRecord are in the same namespace...

kari.marttila13:11:21

But if I put EmailRecord into another namespace then Clojure complains that it cannot find function lowercase...

kari.marttila13:11:57

(def ourcompany (->EmailRecord "CoolCompany")) (lowername ourcompany "David") => "david" (email ourcompany "David") => "[email protected]"

kari.marttila13:11:50

So, if defrecord EmailRecord is defined in another namespace, the Clojure complains that: Unable to resolve symbol: lowername in this context

jaihindh.reddy13:11:24

Please evaluate the following forms in your repl.

jaihindh.reddy13:11:15

(ns pro)
(defprotocol EmailProtocol
 (lowername [this name])
 (email [this host]))
(ns user)
(require '[pro])
(defrecord EmailRecord [ourcompany]
  pro/EmailProtocol
  (lowername [this name] (clojure.string/lower-case name))
  (email [this contractor]
    (let [contractorname (pro/lowername this contractor)
          companyname (pro/lowername this ourcompany)]
      (str "ext-" contractorname "@" companyname))))
(def ourcompany (->EmailRecord "CoolCompany"))
(pro/lowername ourcompany "David")
(pro/email ourcompany "David")

jaihindh.reddy13:11:30

You wanna require and namespace qualify the protocol.

jaihindh.reddy13:11:38

Hope this helps.

kari.marttila13:11:17

Damn, that worked. Why didn't I figure that out. πŸ™‚

jaihindh.reddy13:11:34

I defined the protocol (abstraction) in the namespace pro and depend on (`require`) the abstraction in the implementation, the user namespace.

jaihindh.reddy14:11:58

In fact, the definition of the protocol, the record/type, and the coupling of the protocol and the implementation can be in three different namespaces.

jaihindh.reddy14:11:05

With extend-type

jaihindh.reddy14:11:32

This means you can extend a third party type to a protocol by yet another third party in your namespace.

kari.marttila14:11:33

Ok. Good to know. I'm just learning how to use protocols...

kari.marttila14:11:48

They seem to be very powerful abstraction.

jaihindh.reddy14:11:32

This is Clojure's solution to the expression problem. https://en.wikipedia.org/wiki/Expression_problem

sova15:11:43

who needs types anyway

sova15:11:57

everything is a pixel type πŸ˜›

souenzzo17:11:25

(seq my-sorted-map) will always return entries in order?

sova21:11:47

Hi, how can I append into an atom?

sova21:11:12

(def tv-state {:tales [{m1} {m2} {m3}]})

sova21:11:24

I want to (swap! tv-state ??? [:tales] m4)

sova21:11:49

to get tv-state {:tales [{m1} {m2} {m3} {m4}]}

sova21:11:32

? did you delete your solution? it worked haha

marc-omorain21:11:42

I wanted to test in a repl πŸ˜„

sova21:11:04

XD i just tried it and it works perfectly

marc-omorain21:11:18

(swap! tv-state update :tales conj m4)

sova21:11:18

(swap! tv-state update :tiles conj new-post-map)

sova21:11:28

thanks πŸ˜„

marc-omorain21:11:02

I took me a mental leap to understand that the first time.

marc-omorain21:11:25

You are calling update on the the value of tv-state

marc-omorain21:11:42

and you are passing conj new-post-map as the arguments to update

sova21:11:36

i kept putting [:tiles] instead of just :tiles

sova21:11:06

so many tabs in search of the answer... so thanks πŸ˜„

schmee21:11:31

how do I ignore a variable when unifying in core.logic? the usual suspect of _ fails in this case: (== x [_ b])

taylor23:11:07

Do you have a larger example?

taylor23:11:51

not sure if this is what you’re looking for, but you could introduce a new, unbound logic variable in that position: (== x [(lvar) b])

seancorfield22:11:20

@sova If you use update-in, you can pass [:tiles] -- just in case you want to go deeper into a nested structure and need multiple levels.