Fork me on GitHub
#beginners
<
2018-11-20
>
stardiviner02:11:08

Does Clojure has SimHash algorithm implementation or wrapper on Java libraries? I search clojars, not found. only one cascading-simhash. And I also did search on Maven, don't know choose which one. Does anyone knows similar library of implementation about text similarity comparision.

didibus06:11:32

Do you know of one in Java? Interop is generally very straightforward

didibus06:11:08

I know secondstring is good for string similarity, but I'm not sure it has simhash

ikitommi06:11:27

@jayzawrotny @noisesmith reitit flattens extra sequences, so instead of concatting programmatically, one could just say [(home-routes) (api-routes)]. If you want to have a common root definition, you can also say:

["" {:middleware [middleware/wrap-csrf middleware/wrap-formats]}
  (home-routes)
  (api-routes)]
but in case you want to add common data to all routes, you can also put the under router option :data. Behind the scenes, router :data and all intermediate route data is recursively (meta-)merged to the endpoints, the doing effectively the same.
(ring/ring-handler
  (ring/router
    [(home-routes)
     (api-routes)]
    {:data {:middleware [middleware/wrap-csrf middleware/wrap-formats]}}))
(there is also #reitit)

👍 4
jaide16:11:57

That worked like a charm. Thanks a ton!

ikitommi06:11:33

the automatic flattening of nested sequences is nice, because you can create your routes with things like for and it just works:

(ring/ring-handler
  (ring/router
    [["/ping" {:get (constantly {:status 200, :body "pong"})}]
     (for [i (range 10)]
       [(str "/item-" i) {:get (constantly {:status 200, :body (str "item-" i)})}])]))

Lennart Buit10:11:04

(I feel like I am asking many questions, if it is bothering please say!) I have a record from a library for which I want to implement a own-defined protocol. So I created a namespace that calls extend_type with that record and a custom implementation of that protocol. What I don’t quite understand is where to require this namespace. The library is the instantiator of those records and when they reach my code I want to treat them like my protocol dictates. Is there some documentation on this?

didibus10:11:11

Require it everywhere you want to use the records in an extended fashion

Lennart Buit10:11:11

As in everywhere-everywhere, or only on the spot where that record enters my code

didibus10:11:04

Well, everywhere that you are also requiring the library

didibus10:11:35

I mean, technically, it is just that you need to have evaluated extend-type once after the record was defined.

Lennart Buit10:11:51

Hmm, that sounds reasonable

Lennart Buit10:11:40

It doesn’t work yet, but probably my bug

didibus11:11:25

(do
  (ns first)
  (defrecord Animal [name])
  (ns second)
  (defprotocol PAnimal
    [get-name [this]])
  (extend-type first.Animal
    PAnimal
    (get-name [this] (:name this)))
  (ns third)
  (require '[first :as f])
  (require '[second :as s])
  (s/get-name (f/->Animal "dog")))

Lennart Buit11:11:16

Yeah it works like I expect it in my repl, but not in my app

Lennart Buit11:11:24

so its probably something I am doing stupidly

llsouder11:11:40

(println "does clojure bot eval code")

didibus11:11:31

It does if you add /clj before it. Doesn't always work that well though

didibus11:11:04

Like /clj (+ 1 2)

jaihindhreddy-duplicate16:11:06

When using EDN as config files, is there a way to express DAGs or better yet (arbitrary fully connected graphs) in EDN?

didibus20:11:41

Isn't that just a Map?

didibus20:11:38

{:a :b 
 :b :c 
 :c :a}

Alex Miller (Clojure team)16:11:56

make an index

👍 4
jaihindhreddy-duplicate20:11:42

How do I make rebel-readline execute (use 'clojure.repl) on startup?

jaihindhreddy-duplicate20:11:08

This doesn't work: clojure -A:rebel -e"(use 'clojure.repl)"

dpsutton20:11:13

Is something missing from the default repl environment that rebel provides?

jaihindhreddy-duplicate20:11:14

Here's deps.edn:

{:deps {org.clojure/clojure {:mvn/version "1.10.0-beta7"}}
 :aliases {:rebel {:extra-deps {com.bhauman/rebel-readline {:mvn/version "0.1.4"}}
                   :main-opts ["-m", "rebel-readline.main"]}}}

noisesmith20:11:55

can you add the -e to the :main-opts?

noisesmith20:11:40

oh -it's an init-opt not a main-opt

jaihindhreddy-duplicate20:11:27

@dpsutton it shows function arglists as you type, indents code, rainbow parens by default, and some other comfy features.

jaihindhreddy-duplicate20:11:37

I'm getting: Error building classpath. Unknown alias key: :init-opts

jaihindhreddy-duplicate20:11:26

{:deps {org.clojure/clojure {:mvn/version "1.10.0-beta7"}}
 :aliases {:rebel {:extra-deps {com.bhauman/rebel-readline {:mvn/version "0.1.4"}}
                           :init-opts ["-e", "(use 'clojure.repl)"]
                           :main-opts ["-m", "rebel-readline.main"]}}}

dpsutton20:11:02

Yes I know that. I'm wondering what it is missing that is promoting you to include clojure.repl

jaihindhreddy-duplicate20:11:43

Also pprint for which I need to do (use 'clojure.pprint)

noisesmith20:11:14

yeah - clojure.repl is pretty important (though rebel-readline does do its own version of those in a pretty way)

jaihindhreddy-duplicate20:11:08

This causes an exception: :main-opts ["-e" "(use 'clojure.repl)" "-m", "rebel-readline.main"]

seancorfield20:11:40

You need a comma , instead of space in the use.

jaihindhreddy-duplicate20:11:15

I'm sorry I don't follow.

seancorfield20:11:29

"(use,'clojure.repl)"

parrot 4
seancorfield20:11:08

Because clj writes options to a file and reads them back in via the shell, spaces do not work. But since Clojure accepts comma as whitespace, you can use , instead.

seancorfield20:11:03

See https://github.com/seancorfield/dot-clojure/blob/master/deps.edn for heavier uses of comma-as-whitespace (and as possible inspiration for other deps.edn stuff).

👍 4
jaihindhreddy-duplicate20:11:13

It is a bit weird though that commas have to be used.

jaihindhreddy-duplicate20:11:00

Is this fixable somehow by escaping stuff?

dpsutton20:11:25

You could use perhaps user.clj?

andy.fingerhut20:11:31

I would say that most escaping tricks are at least a bit weird, if not more so.

andy.fingerhut20:11:02

especially when you start dealing with 2 independent levels of escaping at different steps, for the same set of characters.

☝️ 4
Alex Miller (Clojure team)20:11:15

the “Corfield Comma”

😄 16
😈 4
💯 4
noisesmith20:11:50

I don't know enough about deps implementation and shell escaping to say for sure, but one would hope at least that it would be possible to preserve the whitespace without resorting to commas

Alex Miller (Clojure team)21:11:43

I believe it’s possible to fix but it’s something that’s going to a) suck and b) take a while

noisesmith21:11:59

yeah - I know escaping around sh isn't straightforward

Alex Miller (Clojure team)22:11:59

it’s going in and out of bash vars, Java, and files

Alex Miller (Clojure team)22:11:19

I’m sure it’s possible to do, I just have had better things to do so far :)

eggsyntax00:11:41

I happen to be going back and forth between bash and clj at the moment in a side project, and I’ll wholeheartedly second the suckiness 😜

seancorfield21:11:11

I'm sure Alex would entertain patches to "fix" this 🙂 Good luck 🙂

😅 4
andy.fingerhut21:11:53

Or maybe implement *print-readably* for bash? 🙂

Lennart Buit21:11:36

With regards to the earlier problem I encountered, I was wondering what the reasoning was about the output of the above below program. I expected the latter valid call to return true, as I had (at that point) implemented SomeProtocol for the SomeRecord, but that is not the case. Does this have to do with how that protocol is captured by the closure produced by satisfies-protocol??

didibus06:11:54

Hum, I can think of two things maybe. First, s/def is a macro, and so I'm not sure how it resolves the call to your satisfies-protocol? function. So it might just be that your spec isn't working and everything is always false for it.

didibus06:11:44

Well, actually that's the only guess I have

Lennart Buit06:11:49

Nah the problem is the closure on line 12 that captures the protocol definition at that point in time

didibus06:11:22

What closures?

Lennart Buit06:11:23

The protocol definition is updated on line 17, but not in the variables that the closure on line 12 has captured

didibus06:11:27

Are you sure? How did you validate that hypothesis? I'd be surprised if the closure makes a clone of the protocol. It would seem to me this would just copy over the reference to it

Lennart Buit06:11:17

well that is what I am getting from the discussion below ^^

Lennart Buit06:11:53

not an expert obviously, this bit me yday :’)

didibus06:11:25

Hum, okay, hadn't read all the convo that follows. Wow, if extend uses alter-var-root, that's pretty weird.

Lennart Buit06:11:59

yeah, couldn’t figure it out either yday, only when I started making that minimal example it started to click slowly

didibus07:11:00

I just always assumed protocols were defined in a global map, but it seems that they each get a Var which is mutated when the protocol is extended with the new version of the protocol. That's kind of weird. The implementation also doesn't seem to take a lock, I wonder if extending a protocol can have race conditions

didibus07:11:43

Oh, forgot that alter-var-root is atomic, so its fine. I guess it actually makes sense. When you defprotocol, like all other def, you're creating a var and assigning it to something. And the protocol hold a map from Type to method implementation. But the protocol is immutable itself. So extending is really creating a new protocol with more implementations set on its map, and updating the Var to point to the new protocol. Cool, learned something today.

Lennart Buit07:11:00

cool right, I also learned something today ^^

Lennart Buit21:11:28

It feels like that SomeProtocol is secretly being mutated, but not in the closure created by satisfies-protocol?.

Lennart Buit21:11:13

I tried plenty of things, like instead ‘normal’ defing the result of the partial application so to say, but as soon as I have a closure that captures that protocol it seems to regard later-defined implementations to not satisfy the captured protocol. Whereas if I would do the capture after, it works fine

Lennart Buit21:11:35

If that makes any sense 😛

noisesmith21:11:46

this can happen when you reload the file that defines the protocol - now there's two protocols with the same name, and existing objects likely don't implement the new one

noisesmith21:11:14

I wonder what's going on without a reload though

noisesmith21:11:12

@lennart.buit if it helps, putting the extend-type before the s/def makes it return true

Lennart Buit21:11:44

That I know, I just can’t in my particular usecase

bronsa21:11:19

use

(defn satisfies-protocol?
  [prot]
  (fn [val] (satisfies? @prot val)))
and
(s/def ::some-protocol (satisfies-protocol? #'SomeProtocol))

bronsa21:11:29

extend works by alter-var-rooting

didibus07:11:29

Had to look at the impl. It kinda feels like Protocols are one of those things that would have been better of made mutable.

noisesmith21:11:36

ahh - because the protocol was caputured but later mutated?

bronsa21:11:51

your definition grabs the value of the var instead of dereferenging the var at every invocation

👍 4
Lennart Buit21:11:07

I suspected something like that to happen

Lennart Buit21:11:52

I spent the better part of my work day on that :“)

bronsa21:11:36

if satisfied? accepted a var instead it would avoid this issue

Lennart Buit21:11:43

Sorry - satisfied?, did you mean satisfies? or …? I am not sure I am following

Lennart Buit21:11:56

ahhh var in that sense, right you mean that if satisfied? would deref itself

bronsa21:11:26

yeah satisfies? sorry

Lennart Buit21:11:48

Thank you at least, I now know that my hunch was correct and I learned something about the internals ^^

noisesmith21:11:11

yeah - my mind was blown when I first looked at the metadata on a protocol - given enough time I like to think I might have put (+ 2 2) together and realized what was happening here with the scope capture

andy.fingerhut21:11:45

Love "I might have put (+ 2 2) together" ❤️ Slightly nerdier: "I might have eval'd (+ 2 2)", but gets harder to understand then.

😄 4
Lennart Buit21:11:36

Yeah, I think I’ll make my satisfies-protocol? a macro that does the ref/deref ceremony so that i can keep my call sites the same, but have an actual working function

Lennart Buit22:11:43

or — a function that works in all cases

reborg23:11:05

Shouldn’t just be (s/def ::some-protocol #(satisfies? SomeProtocol %))? It seems to work for me

Lennart Buit06:11:10

Yeah, but this is so common in my codebase that I like to not have anonymous functions floating about

bronsa11:11:41

well yeah, inlining the protocol name gets away with the root cause of the bug, as the protocol is dereferenced inline everytime

Lennart Buit11:11:05

I solved it by making a macro called satisfies-protocol? that has the exact same way of being called, but instead generates that anonymous function

Lennart Buit11:11:18

So like this:

(defmacro satisfies-protocol?
  [proto]
  `(fn [val#] (satisfies? ~proto val#)))

Lennart Buit11:11:38

And it can then be used exactly the same: (s/def ::some-protocol (satisfies-protocol? SomeProtocol))

reborg11:11:06

What’s wrong with anonymous functions floating around?

reborg11:11:12

If debugging is the issue, would still prefer (s/def ::some-protocol (fn satisfies-protocol? [o] (satisfies? SomeProtocol o))) to a macro

Lennart Buit11:11:01

Nothing really except for taste. I just have a lot of these specs and I prefer not to change all uses to such an anonymous function.

Lennart Buit11:11:25

Keep the “workaround” local instead of littered around the codebase

noisesmith23:11:52

oh - yeah the function should do a fresh lookup of the var by symbol when called

reborg23:11:40

A macro to produce the same validation for other protocols:

(defmacro sspec [proto] 
  `(s/def ~(keyword (str (.getName *ns*)) (str proto)) 
      #(satisfies? ~proto %)))
(sspec SomeProtocol)
(s/valid? ::SomeProtocol (->SomeRecord))
;; true