Fork me on GitHub
#clojure
<
2017-05-06
>
ragsboss01:05:39

hi guys I believe I found a potential bug with https://github.com/clojure/core.match

user=> (def ACTIVE true)
(def ACTIVE true)
#'user/ACTIVE
user=> (match [nil] [ACTIVE] 1)
(match [nil] [ACTIVE] 1)
1
or perhaps i may be doing something wrong.. any clues? whereas the same thing, if I use true directly works as expected
user=> (match [nil] [true] 1)
(match [nil] [true] 1)

IllegalArgumentException No matching clause:   user/eval6529 (form-init8320221599224080614.clj:1)

qqq02:05:32

@ragsboss : I am NOT a developer of core.match. However, (1) I can replicate the problem you have reported and (2) I agree with you in that I'm not expecting it to match.

ragsboss06:05:34

qqq: @qqq thank you for your input on this. I realized what I was doing wrong. The way I’m using it ACTIVE inside the match will bind to the matched value instead of what we naturally expect.. this is explained in https://github.com/clojure/core.match/wiki/Overview#Local scope and Symbols.. I found this unintuitive but not sure how to report it as I see no way to contact the authors of this package..

qqq08:05:41

@ragsboss : oh, so the point is "ACTIVE" is a global, NOT a local, thus it binds ACTIVE instead of looks up the vaule of ACTIVE ?

Oliver George12:05:00

I suspect the clojure JIRA server has a place for core.match but I can't see a solution to avoid the surprise short of improved documentation.

Oliver George02:05:15

I think the confusion is "matching literal" vs "binding"

xiongtx04:05:02

I’ve a map like:

{k1 v1
 k2 v2}
where k1 and k2 are strings and the (nonzero) values of v1 and v2 should sum to 0. Given such a map, I’d like to destructure it and bind the k for positive v to a var (call it to) and k for negative v to another var (call it from). However, either v1 or v2 could be the pos/neg value. Is there a way to do this without an if? core.{logic, unify} maybe (though that seems a bit heavy-handed)?

noisesmith04:05:57

(let [[[k1 v1] [k2 v2]] (sort-by val m)] ...)

xiongtx19:05:11

noisesmith: An elegant solution--thanks!

noisesmith04:05:50

or with the other names (let [[[from v1] [to v2]] (sort-by val m)] ...)

noisesmith04:05:55

+user=> (let [[[from v1] [to v2]] (sort-by val {:a 2 :b -2})] [from to])
[:b :a]

qqq05:05:45

(defn foo [^:bar x]
  ... is there anything I can do here
  ... which will get me the value :bar
 )

gmercer06:05:37

(defn foo [^:bar x] (prn x)) (defn get-hint [the-fn] (map meta (first (:arglists (meta the-fn))))) (get-hint #'foo) ({:bar true}) you can outside but maybe it is very unlikely whilst the var is being defined

gmercer06:05:21

i.e (defn foo [^:bar x] (let [qqq (get-hint #'foo)] (prn qqq))) won't work

qqq06:05:00

@gmercer : in summary: outside; possible inuside :not obvious how to do the (:arglists (meta the-fn)) 'trick' is realy cool

qqq06:05:06

I never thought of that; thanks!

gmercer06:05:09

@qqq see last statement of (source defn) for clues

qqq08:05:20

I realize many make the argument that "clojure doesn't need 'design patterns'" because functional programming and macros

matan09:05:45

qqq: I think saying that is simply wrong ― regardless any original quotes you may have on it. You learn to develop patterns which you reuse to similar situations. Every human being does that. Just the Java worshiped design patterns aren't all very applicable, although some mathematical isomorphisms may apply.

lincpa11:05:52

@qqq OO and FP are a kind of generalized design pattern, it's no difference (excessive application of OO & FP) and (crazy application design pattern in Java). I think the "Data structure + algorithm" is more real, more essential. The system consists of clean data streams and simple function streams.

georgberky11:05:17

Couldn't we argue that monads are functional design patterns whereas Singleton an the like are OO design patterns?

leonoel11:05:53

A pattern is a template of code you rewrite each time you have to tackle a problem of a given category. 'design patterns' generally refers to the gof, which is often mocked by functional programmers because many of the patterns listed in the book are in fact situations where functional style is better suited than OO style. Of course when you use functional style in an object-oriented language the result is a lot of boilerplate code, that is, a "pattern".

leonoel12:05:39

A wise man once said something like "when I see a pattern, I see a language flaw" (I guess it was RH but can't remember where). That is, in a good language, anytime you happen to rewrite many times the same things, you make an abstraction. Macros, functions, monads are tools for creating abstractions, avoiding patterns.

lincpa12:05:18

All the things around are algorithmic patterns, my algorithm prototype from Enterprise management ideas, such as industrial assembly line, total corporate model, Group financial center, etc.

mobileink18:05:55

a pattern is just a cumbersome abstraction with poor language support.

wiseman21:05:56

peter norvig might agree with you, but richard gabriel disagrees.

mobileink21:05:04

links, please? never heard of 'em.

qqq08:05:55

@U0LGCREMU : to be serious, he wrote a nice book "Paradism of AI PRogramming" -- I thikn that's what was being referred toi

qqq08:05:06

@U053XQP4S : lol, I like how it reduceds the command pattern down to:

(defn execute [command & args]
  (apply command args))

(execute db/login "django" "unCh@1ned")

qqq08:05:28

however, is there a book of common 'clojure patterns' ?

qqq08:05:49

I often feel when coding that I have working, but ugly code; whereas there should be some idiom that solves the problem cleanly

matan09:05:26

@qqq until such a book is written, I think you can ask for per-case suggestions here once in a while. maybe there are books about "functional programming" or "lisp" patterns not necessarily clojure ones, the number of clojure practitioners might be too small to yield books.

lsenta10:05:05

Joy Of Clojure? "Thinking the Clojure way" seem's to be the premise you're looking for @qqq

matan11:05:22

read this book several years ago, I am not sure it is the best functional patterns dictionary out there. more of a high-level tour for the simple idioms. I might be wrong of course.

matan11:05:36

in clojure, in jargon and otherwise, what are the differences between a form and an expression?

lincpa11:05:52

@qqq OO and FP are a kind of generalized design pattern, it's no difference (excessive application of OO & FP) and (crazy application design pattern in Java). I think the "Data structure + algorithm" is more real, more essential. The system consists of clean data streams and simple function streams.

gmercer12:05:51

@qqq possibly a bit way out .. The Little Schemer - actually do the exercises in Dr. Racket, Practical Common Lisp - again Dr. Racket is your friend, How To Design Programs (Scheme) MIT Press ... these recommendations are relevant if you are referring to breaking your imperative programming habits - also watching MIT 6.001 Structure and Interpretation https://www.youtube.com/watch?v=2Op3QLzMgSY&amp;list=PLE18841CABEA24090

michaellindon14:05:16

If you were writing an user facing API for some software that you've written, and you wanted to add a verbose option, what would be the most elegant way to achieve this? My knee jerk reaction would be to litter my code with (if verbose print.... Etc but this seems messy and inelegant to me. Is there some other magic I could work with macros for instance to create verbose versions of my functions?

noisesmith14:05:41

doesn't this map directly to log levels?

noisesmith14:05:08

with the right log formatter it could work

michaellindon14:05:09

@noisesmith this looks very relevant, I haven't used or seen this before, thanks for the suggestion I'll check it out :)

oskar13215:05:15

hey everyone, I am new to clojure and STM and have a question, a ref's value is protected accross threads? that is if I have threads 1 and 2 and both execute a transaction in which they alter the same ref, one of those transactions will fail because a write was done before and retry? or is it only in a single thread? thanks a lot for your help

noisesmith15:05:52

you can't possibly have two transactions at once in one thread

noisesmith15:05:00

the point of STM is to protect data across threads

oskar13215:05:14

that's great! thanks a lot!

noisesmith15:05:20

also, in real code, we rarely need refs/transactions, usually our updates to shared state are rare enough that using an atom and the swap! function suffices

oskar13215:05:47

that was my next question, I have a very specific case in which I'm not sure if a ref is best option. Can I DM you and explain it?

noisesmith15:05:21

sure, but you can also discuss it here

oskar13215:05:06

I wish to create a course registration system that can be accessed by multiple students at the same time. So I have multiple schools which have multiple courses each. Each course has a number of available spots. Given that all the students should be able to register for courses at the same time (no matter the school), I thought that using a ref for each course should be the best option in order to avoid "overbooking of the courses" and also not blocking every course during a transaction.

noisesmith15:05:01

for something like a course, wouldn't you want the data to persist if the server restarted?

noisesmith15:05:10

this sounds more like a db thing

oskar13215:05:29

this is a personal project

oskar13215:05:35

I wish to do everything in memory

oskar13215:05:56

and mostly learn how to deal with parallelism and concurrency

noisesmith15:05:09

OK - the easier way to do this is to have an atom with a hash-map with keys for each course

noisesmith15:05:56

you can also use refs of course, but usually we don't turn to those until the contention on the atom is hurting performance

oskar13215:05:24

will try with an atom and see performance

oskar13215:05:31

then I'll try with a ref

oskar13215:05:56

thanks for your help

noisesmith16:05:11

there's very little to this, but I find it useful so I figured I'd share: it's a lein project with no code, only a few dependencies, designed to create an uberjar for running a stand alone clojure with a few favorite deps https://github.com/noisesmith/bench

noisesmith16:05:47

you probably would want a different list of static deps, but since it's a one file repo that's a pretty simple thing to fix up

paulspencerwilliams18:05:02

Can anyone offer any advice on why attempting to open a website using up to date Selenide using

(import [com.codeborne.selenide Selenide])
(Selenide/open "")
opens the website using Firefox, but after around a minute closes WebDriver down with
May 06, 2017 7:27:55 PM com.codeborne.selenide.impl.WebDriverThreadLocalContainer closeUnusedWebdrivers
INFO: Thread 20 is dead. Let's close webdriver FirefoxDriver: firefox on ANY (da9dc339-3f7f-bb4f-aeec-953fefd1bf52)
May 06, 2017 7:27:55 PM com.codeborne.selenide.impl.WebDriverThreadLocalContainer closeWebDriver
INFO: Close webdriver: 20 -> FirefoxDriver: firefox on ANY (da9dc339-3f7f-bb4f-aeec-953fefd1bf52)
May 06, 2017 7:27:55 PM com.codeborne.selenide.impl.WebDriverThreadLocalContainer closeWebDriver
INFO: Close proxy server: 20 -> null
May 06, 2017 7:27:55 PM com.codeborne.selenide.impl.WebDriverThreadLocalContainer$CloseBrowser run
INFO: Trying to close the browser FirefoxDriver ...
1494095275784	Marionette	INFO	New connections will no longer be accepted
[Child 5121] ###!!! ABORT: Aborting on channel error.: file /builds/slave/m-rel-m64-00000000000000000000/build/src/ipc/glue/MessageChannel.cpp, line 2143
[Child 5121] ###!!! ABORT: Aborting on channel error.: file /builds/slave/m-rel-m64-00000000000000000000/build/src/ipc/glue/MessageChannel.cpp, line 2143
May 06, 2017 7:27:56 PM com.codeborne.selenide.impl.WebDriverThreadLocalContainer closeWebDriver
INFO: Closed webdriver in 264 ms
It appears to be something about the Repl. Native Java invoking the same api works fine.

noisesmith18:05:39

how are you starting clojure?

noisesmith18:05:45

my hunch is that clojure itself is unlikely to break the tool, but something in nrepl, REPLy, or leingengen, or boot etc. is more likely to be the culprit

paulspencerwilliams18:05:13

lein repl or creating a repl using Cursive.

noisesmith18:05:23

right, and cursive is using lein

paulspencerwilliams18:05:31

lein new repl
and adding
[com.codeborne/selenide "4.4.3"]

noisesmith18:05:36

I'd try lein trampoline repl which elminates the nrepl factor

noisesmith18:05:19

and you can also try making an uberjar and running it with java -cp target/foo-standalone.jar -m clojure.main which also eliminates leinengen from the picture

paulspencerwilliams18:05:41

@noisesmith trampoline hasn’t resolved it. Will try and uberjar. Cheers!

noisesmith18:05:33

just fixed that uberjar invocation, and if the problem continues, I'd be interested to see what gdb says the program was doing around where that error happens...

paulspencerwilliams18:05:32

@noisesmith just running using ..

(ns selenium-exploration.core
  (:import (com.codeborne.selenide Selenide))
  (:gen-class))

(defn -main
  [& args]
  (Selenide/open "")
  (Thread/sleep 100000))

paulspencerwilliams18:05:04

actually, that was a

lein run
than ran for 100 seconds fine.

paulspencerwilliams18:05:56

Died invoking (-main) in the repl.

paulspencerwilliams19:05:19

Odd,

lein repl
running
(defn -main
  [& args]
  (Selenide/open "")
  (Thread/sleep (* 3 60 1000)))
loads the browser, which sits around for 4 minutes (3 minutes during Thread.sleep) and then a minute after. It always appears to last a minute after being in scope….

noisesmith19:05:55

(shutdown-agents)

noisesmith19:05:26

anything which used clojure's agent pools needs to call that to exit promptly

paulspencerwilliams19:05:30

Not following. You suggest I call this? How would shutting anything down help to keep something (the web driver or associated thread) alive? I’m new to (shutdown-agents)

paulspencerwilliams19:05:42

Unless you’re basically advising a change to keep it ‘in scope’. I’m just trying to assign the driver to an atom.

noisesmith19:05:54

oh - sorry - I mean not calling (shutdown-agents) is what makes it last another minute after that

paulspencerwilliams19:05:17

okay, that makes a bit more sense. Thank you 🙂

noisesmith19:05:54

maybe you just need for -main not to exit? if that's the case you can just do @(promise) - guaranteed not to exit

paulspencerwilliams19:05:01

Trying that, the atom attempt failed.

paulspencerwilliams19:05:30

That seems to be working.

noisesmith19:05:32

for something more sophisticated, if you have other stuff running too, you can have the main block on a promise, and then deliver to the promise when you are OK with it exiting

noisesmith19:05:24

my assumption is that Selenide is somewhere starting a thread that's set as a daemon, so that if all the non-daemon threads exit it does too

paulspencerwilliams19:05:09

So would a repl start a new thread for each command possibly?

noisesmith19:05:20

no, not at all

noisesmith19:05:33

so clearly something different is going wrong in the repl...

paulspencerwilliams19:05:16

Selenide specifically isn’t a requirement for me, Selenium that it wraps is, so I’ll try with that. Maybe Selenide adds a more complex threading model.

paulspencerwilliams19:05:06

Thanks for the help, I’ll keep digging for a while and try selenium direct.

bradford23:05:30

Is there a Ring to Netty adapter that's more up-to-date than https://github.com/RallySoftware/netty-ring-adapter ? I'm having to do some ... unsavory things

ragsboss06:05:34

qqq: @qqq thank you for your input on this. I realized what I was doing wrong. The way I’m using it ACTIVE inside the match will bind to the matched value instead of what we naturally expect.. this is explained in https://github.com/clojure/core.match/wiki/Overview#Local scope and Symbols.. I found this unintuitive but not sure how to report it as I see no way to contact the authors of this package..