Fork me on GitHub
#clojure
<
2017-05-05
>
arthur00:05:20

sorry is this is a tired old question, what is the right and proper type to extend a protocol with if I want this implementation to be called for all kinds of core.async channels?

noisesmith00:05:38

@arthur are you looking for clojure.core.async.impl.protocols/ReadPort and WritePort ?

noisesmith00:05:02

that is what I needed to check for to write a chan? function

arthur00:05:44

if the first argument to the implementation function is any kind of chan, then this function should be called

arthur00:05:44

I want to extend a protocol such that the implementation receives a chan

noisesmith00:05:08

there’s also Channel (same namespace)

arthur00:05:26

that sounds better than clojure.core.async.impl.channels.ManyToManyChannel

noisesmith00:05:28

I don’t remember that existing when I wrote my chan? predicate, it would have been the natural thing…

arthur00:05:46

which seems overly specific

noisesmith00:05:08

oh wait, the ports were totally wrong, I’m misremembering something

noisesmith00:05:52

double self correction, heh

=> (supers (class (clojure.core.async/chan)))
#{clojure.core.async.impl.protocols.Channel java.lang.Object clojure.lang.IType clojure.core.async.impl.protocols.WritePort clojure.core.async.impl.protocols.ReadPort clojure.core.async.impl.channels.MMC}

grounded_sage02:05:51

how do I go about referencing the previous state of an atom?

joshjones03:05:48

@grounded_sage when you change an atom via swap! or reset!, you can use a watch to get the old value https://clojuredocs.org/clojure.core/add-watch

lincpa03:05:50

watch -> log

joshjones03:05:01

@grounded_sage also, an upcoming release of clojure will have support for accessing the previous version using swap, instead of the new version. in the meantime, see something like this: http://stackoverflow.com/questions/43599473/get-the-state-of-an-atom-and-reset-it-atomically/43599982?s=3%7C0.0000#43599982

joshjones03:05:34

beyond that, from a 10 second glance at the java code, once an AtomicReference is set, there's no looking back at the previous value

grounded_sage03:05:53

@joshjones you mean like you can swap back to a previous version? That definitely sounds good. Pretty much what I am needing to do now. Swap in some new content but then swap back.

joshjones04:05:36

as posted above @grounded_sage , this will return the prior value:

(defn reset-return-old!
  [atm new-value]
  (let [old-value <@U169ZE1J4>]
    (if (compare-and-set! atm old-value new-value)
      (do
        (.notifyWatches atm old-value new-value)
        old-value)
      (recur atm new-value))))
You can then do whatever you like with it.. this is just a reset, but swap is the same idea

achesnais05:05:27

Hi all, does anyone know of a natural language API similar to IBM Watson’s personality insights? What I’m looking for is a service that analyses unstructured text, but does more than just sentiment analysis or entity extraction, and whose results are more directly useable

jimmy05:05:42

@achesnais this would be a good discussion for #off-topic

achesnais05:05:55

ah right, fair enough ^^

qqq08:05:21

does clojure havea function which captures the idea of: here's a list of functions, try them all, in this order, and return me the firt one that succeeds

qqq08:05:30

so I have some x, and a bunch of f1, f2, f3, ....

qqq08:05:39

and I want the first of (f1 x), (f2 x) .... that succeeds

lincpa08:05:08

(or (f1 x) (f2 x) ) ?

placeboza08:05:10

Curiousity question ... Is anybody here using clojure in an enterprise/large corporate distributed system way? .. if so, what kind of system architecture did you use? Micro-services?

placeboza08:05:28

at this stage, enterprises still tend to prefer java/.net and object-oriented designs

placeboza08:05:39

hence my curiosity

placeboza08:05:02

if you want to know more of what I mean by enterprise/large corporate... imagine a large bank

placeboza08:05:34

or anything sizeable

lincpa09:05:20

@qqq (some #(% x) fnseq)

noisesmith15:05:14

lincpa: qqq: there’s also some-fn, but neither of these returns the function (which is how I initially read the question)

(ins)user=> (some #(% 2) [list? odd? even?])
true
(ins)user=> ((some-fn list? odd? even?) 2)
true

pesterhazy10:05:25

How do people solve indentation issues in a team? The problem: team members use {Atom, IntelliJ, Emacs}. True to its name, my Emacs's aggressive-indent mode reformats code it touches (or it seems just sees) with much enthusiasm, leading to diff noise. How do you approach this technially trival yet socially complex issue?

agile_geek10:05:06

Although that either means you need to include cljfmt in your build pipeline (with a potential commit if you use fix mode) or add git hooks to run it.

mpenet10:05:52

or have a rule that it must pass cljfmt prior to committing

mpenet10:05:04

it's quite easy

agile_geek10:05:16

You can customise the indent policies on most of those editors (including emacs) so you could produce std formatting across all editors.

agile_geek10:05:45

@mpenet relies on ppl remembering tho

mpenet10:05:07

same for tabs vs space, it's a rule ppl must follow

mpenet10:05:20

a lot of editors have cljfmt plugins

mpenet10:05:36

well the main ones at least

agile_geek10:05:24

tabs vs spaces is usually something u set in your editor tho. So fire and forget. cljfmt plugins are good way to go

mpenet10:05:53

cider follows cljfmt rules by default

mpenet10:05:17

i think cursive might as well

agile_geek10:05:23

Cursive differs a bit around alignment of vars

agile_geek10:05:45

but both can be customised

pesterhazy10:05:04

yeah I was wondering how an automated tool might fit in

pesterhazy10:05:48

The main point of contention is indenting function arguments, essentially boiling down to the three options laid out here: https://github.com/clojure-emacs/clojure-mode#indentation-options - always-align, always-indent, align-arguments

rauh10:05:50

git status -> take the changed files -> Use lumo + clj-fmt to rewrite the files. That could be nice.

pesterhazy11:05:04

why lumo? because it's faster?

rauh11:05:20

It'd be a standalone tool instead of having a lein/boot

placeboza11:05:41

@pesterhazy If you're using the right GIT indentation config, I think that issue would go away...

pesterhazy11:05:03

what's git got to do with it?

placeboza11:05:17

I'm saying if you're sharing your code in the team via a git repo

placeboza11:05:26

and you've set the indentation handling config

placeboza11:05:31

then git would sort it out for you

placeboza11:05:37

so I know my answer assumes a lot

placeboza11:05:40

just throwing it out there

pesterhazy11:05:13

we're using git, but can you point me to a reference where git reindents lisp code?

placeboza11:05:39

hmm you know what, I think I'm talking rubbish

placeboza11:05:41

Friday brain

placeboza11:05:50

confusing it with something else

placeboza11:05:20

nevertheless, someone has done what Im suggesting

placeboza11:05:45

not going to auto-indent, but will manage spaces/tabs

pesterhazy11:05:55

tabs v spaces is not the issue in our team. 2 spaces have won the battle luckily 🙂

placeboza11:05:02

ah ok. I see

placeboza11:05:11

nvm then. You're referring to actual formatting issues

placeboza11:05:17

code formatting prettiness concerns

placeboza11:05:14

in which case, I have nothing other than perhaps to have the team try to standardize their preferences 🙂

pesterhazy11:05:16

some editors use this style:

(some-function 10
  1
  2)

pesterhazy11:05:54

others (such as clojure-mode by default) use this style:

(some-function 10
               1
               2)

pesterhazy11:05:24

if two people using those two editors work on the same code, you pingpong back and forth between the two

placeboza11:05:24

right.. although emacs is famously configurable, so..

placeboza11:05:59

perhaps just a matter of choosing a style and putting effort into configuring the tools to match up

pesterhazy11:05:12

right I think that's what it boils down to

pesterhazy11:05:24

perhaps aided by a cljfmt or boot-fmt style

placeboza11:05:40

yup if necessary

placeboza11:05:50

anyway, Im not much help today it seems

placeboza11:05:03

and I have to deploy to production tonight. great. 😛

pesterhazy11:05:56

gonna give cljfmt a spin

mbjarland13:05:10

any suggestions for fast off-heap (preferably, but not necessarily directly on disk) storage of clojure maps? (the assumption being that the data is too large to fit in memory)

mbjarland13:05:12

yeah nippy is good for what it is but as the data does not fit in memory you would then end up doing some kind of management manually

mbjarland13:05:07

i.e. persist one submap per file or something, I was hoping there would be something out there for managing data sets larger than what fits in memory...looking into the datomic dev mode (disk storage), could be an option

mbjarland13:05:17

also looked at map-db with and without a nippy serializer and at carmine (redis api for clojure) but turns out redis requires your data set to fit in memory so that invalidated that option

ghadi14:05:21

datomic +1

sveri14:05:16

Maybe just throw it into a database? You could even convert it to json and use postgres json column feature if you dont want to add datomic to your stack

ghadi14:05:56

fressian or transit work really well as encoding too

curlyfry14:05:04

I thought transit wasn't recommended for storing data? >"NOTE: Transit is a work in progress and may evolve based on feedback. As a result, while Transit is a great option for transferring data between applications, it should not yet be used for storing data durably over time. This recommendation will change when the specification is complete."

mbjarland14:05:26

datomic is nice...if you are ok with locking yourself into a model where you would be shelling out $5k for a license after a year

mbjarland14:05:33

so say I have small maps (fuzzily a couple of screens in a repl), but I have a million of them...or some large number

mbjarland14:05:43

so one map fits nicely into memory, all of them not so much

mbjarland14:05:11

am I correct in assuming that transit, nippy, fressian would all mean that you would be managing the top level keys yourself somehow, and perhaps storing a file per small map or something similarily home-cooked

lvh14:05:45

I thought someone (Greenberg?) did a bunch of work on hitchhiker trees for this purpose

mbjarland14:05:57

yes, found that as well

lvh14:05:18

looks unmaintained but I don’t know how well it works arlready 🙂

mbjarland14:05:42

yeah, my read as well + no clojars artifact so you start by cloning the repo

mbjarland14:05:09

ok so perhaps there is no "one ring to rule them all" answer to the question, sounds like I'll have to do some digging, use datomic (and drink the cool-aid), or revert to storing things in a database as suggested

mbjarland14:05:34

one thing that strikes me as strange though, on the hitchhiker site they state that "Outboard is a simple API for your Clojure applications that enables you to make use of tens of gigabytes of local memory, far beyond what the JVM can manage" and then they provide a redis backend...with redis "data sets that can't be larger than memory" as per redis documentation. Confusing state of affairs there...

mbjarland15:05:17

https://github.com/JetBrains/xodus seems like a potentially viable candidate as well

rauh15:05:16

If you have many small maps then I'd just use leveldb and nippy serialization. Also all depends on your req/s read/write.

mbjarland16:05:40

yeah, that sounds like a viable option, I'll create a sample project and try it out

mbjarland16:05:13

writes are very rare and can be done offline/bulk, reads need to be fast

ghadi16:05:36

I would not recommend nippy personally.

mbjarland06:05:43

Any particular reason for not using nippy?

socksy15:05:45

really dumb question

socksy15:05:53

i have a clojure library i cloned from github

socksy15:05:57

and i've modified

socksy15:05:17

i want to add it into the dependencies of a new project

socksy15:05:23

without publishing it up to clojars just yet

socksy15:05:26

how do i do that?

bostonaholic15:05:58

change the version number in project.clj then lein install

Tim15:05:01

Is this an acceptable way to use a macro:

(defmacro only-without-nil
  [ex]
  (if (some nil? (rest ex))
    nil
    ex))

=> (only-without-nil (+ 2 4 6 nil nil 5))
nil
=> (only-without-nil (+ 2 4 6 10 5))
27

zylox15:05:41

checkouts is an option too i believe

zylox15:05:48

if have it locally

zylox15:05:15

though you have to still list it

zylox15:05:26

so basically what @bostonaholic said

socksy15:05:01

cool, never realised leiningen had an install option

fantomofdoom15:05:47

Hi, any know big web project in clojure on github or bitbucket?

tankthinks15:05:54

Is there a way to conditionally assoc a value into a map literal?

tankthinks15:05:37

so instead of

(merge 
    {:foo "foo"}
    (when x {:x x})))
something like
{:foo "bar"
 (when x :x x)}

bronsa15:05:48

(cond-> {..} condition (assoc :foo bar))

noisesmith16:05:40

I wonder, is there any correct usage of merge that can’t be replaced with conj?

noisesmith16:05:42

I guess trivially there’s (merge) => nil and (conj) => []

mikerod16:05:04

I was surprised before that conj on maps works like merge

noisesmith16:05:06

but if you have a hash map as a first arg, I think conj works for everything merge handles

mikerod16:05:21

just didn’t seem like the same sort of operation to me

mikerod16:05:34

I guess that is good it works? hah

noisesmith16:05:47

also map conj errors would make a lot more sense if conj didn’t accept another map

noisesmith16:05:18

(because the last thing it tries is to treat the arg as a hash-map, so that’s the one you see in the error message)

noisesmith16:05:46

but that horse is out of the barn, no version of clojure will change that behavior

mikerod16:05:52

(conj {} {:a 2 :b 3} [:c 2])

mikerod16:05:58

just seems so odd to me

mikerod16:05:23

@noisesmith what error are you referring to?

noisesmith16:05:48

(ins)user=> (conj {} (list :a :b))
ClassCastException clojure.lang.Keyword cannot be cast to java.util.Map$Entry  clojure.lang.APersistentMap.cons (APersistentMap.java:42)

noisesmith16:05:02

it wants keyword to be a map entry because it wants the list to be a map

noisesmith16:05:09

and that’s the last failure, so it’s the one reported

noisesmith16:05:30

very counterintuitive

mikerod16:05:01

yeah, it’s one of those garbage in, garbage out cases I guess

mikerod16:05:14

well, I guess maybe not, garbage error msg out hah

mikerod16:05:20

I think the surprise-factor to me with conj behavior on maps is just that it accepts other maps

mikerod16:05:38

It just surprises me that that would have even been special-cased in

mikerod16:05:15

(conj {} [:a 5] [:b 6]) that is normal conj-like behavior on a collection. It is adding items (entries) to a collection (the map)

mikerod16:05:00

(conj {} {:a 5 :b 6}) - it is adding items (other maps?) to the collection (the map)

leonoel16:05:05

(def id (reify clojure.lang.IFn (invoke [_ x] x)))
(def one (id 1))

leonoel16:05:26

raises a compilation error is it a known bug ?

noisesmith16:05:34

wow - that’s weird

hiredman16:05:05

at the repl, the compiler will for some "simple" expressions choose to try and interpret code instead of compiling it

hiredman16:05:33

and the interpreter effectively uses apply to invoke functions, which the reify is missing

hiredman16:05:14

(def one ((fn [] (id 1)))) the extra fn here forces the compiler to actually compile the code which then works

hiredman16:05:33

(I dunno if there is an existing issue for that)

leonoel16:05:23

thanks for the explanation @hiredman

noisesmith16:05:14

ahh, so you could fix it by implementing applyTo for it, right?

leonoel16:05:48

is it idiomatic for custom types that implement IFn to define all arities and throw a custom exception when behaviour is undefined ?

hiredman16:05:18

I am usually pretty lazy about it and just implement the arity of invoke I want, but I've also never run in to that error before

mikerod16:05:46

>at the repl, the compiler will for some “simple” expressions choose to try and interpret code instead of compiling it @hiredman this seems weird to me. The main Clj REPL is doing this? Going through the “apply” flow instead of direct invocation? That’d be interesting to look at. Never heard of it.

hiredman16:05:50

sure, there are vestiges of an interpreter in the compiler, which the compiler uses for very simple expressions at the repl

mikerod16:05:11

weird, I’ll have to check that out

hiredman16:05:14

the rules for that are something like: only for top level forms, only for defs, only for defs where the value is directly result of a function call, and only when the arguments to the function call are also simple

hiredman16:05:22

you will pretty much only ever see that behavior when typing stuff in to a repl

frank17:05:17

is it safe to assume that *ns* in the context of macroexpansion is the namespace being expanded at the time?

noisesmith17:05:49

to be pedantic, namespaces aren’t expanded, forms are expanded, and if they use defining forms *ns* is the namespace they mutate

noisesmith17:05:25

which is basically yes - that is where the current definitions will end up unless they use something wacky like intern

wiseman17:05:59

it seemed like @pesterhazy’s real question was how to solve the social problem of code formatting, which i don’t think anyone answered, but is definitely the more interesting and challenging one. i wish i knew the answer to that. some possible strategies: 1. appeal to community standards--if there is a most popular style, just use that. e.g. maybe there’s a reason :always-align is the clojure-mode default. 2. let the person with the most experience in the language be the authority.

wiseman17:05:50

just like with lots of engineering decisions, sometimes people can’t reach a consensus on their own, and someone needs to be the authority that makes a decision for everyone.

pesterhazy17:05:23

good and eponysterical points @wiseman

noisesmith17:05:32

@wiseman cljfmt answers that with “everybody uses what the tool says is right”

noisesmith17:05:46

which is what my team adopted, I have not regretted it at all

wiseman17:05:07

@noisesmith there are definitely tools that have opinions about code that i don’t think everyone, or even most people agree with. it sure can help to have a “community standard”, which is what ideally something like cljfmt would embody

pesterhazy17:05:07

that's the path I'm going down right now

pesterhazy17:05:33

the tool respects bbatsov's guide, so there's double authority there (human & machine)

noisesmith18:05:14

right, it didn’t invent it’s rules out of a vacuum, it implements human invented best practices

noisesmith18:05:03

haha - but that is the current community consensus - you can create more lines with comments

qqq18:05:03

I have a directory of .clj .cljs *.cljc filles. I want to count "lines of code", but not use wc -l . What is suggedsted ?

zacanger18:05:56

cloc or sloc

zacanger18:05:08

oh, i'm too slow.

qqq18:05:33

https://gist.github.com/andrewvc/3161953 <-- this is the first result on google

qqq18:05:39

use this script or something else for sloc?

noisesmith18:05:12

@qqq there’s an app, cloc, you can get it via however you usually get command line apps, it supports clojure

noisesmith18:05:30

I get it via homebrew

noisesmith18:05:39

(or apt at home)

zacanger18:05:16

it's a perl script. also has a node wrapper on npm (npm i -g cloc)

qqq18:05:20

apt-get install cloc ; yeah, it works

qqq18:05:31

surprised my last 3 months of work is only 1.2k loc

qqq18:05:40

this means I wrote about 10 lines / day, or 1 line / hour.

Alex Miller (Clojure team)18:05:54

you mean that’s the output

Alex Miller (Clojure team)18:05:58

you probably wrote a lot more :)

qqq18:05:28

if P = NP, I could have just written the correct 1.2k lines of code and ignored all the churn

qqq19:05:53

https://github.com/clojure/core.match/wiki/Basic-usage <-- are there more detailed examples of guards?

qqq19:05:00

something that shows guards and capturing at the same time

matan21:05:34

very elegant way of anding a list's items?

ghadi21:05:47

probably every?, but you'd have to say more about what you want

matan21:05:52

(every? identity my-list-of-booleans)

matan21:05:09

but might possibly be a more elegant way

zylox21:05:06

true? is an option too if it is booleans and not for truthiness

zylox21:05:19

as your predicate that is

matan21:05:53

right, a tad more readable I think

matan21:05:24

actually this might get better by lazily evaluating the original collection which produces the list of booleans

matan21:05:39

something like while

matan21:05:24

but that will be too specific to and, while or would require a differently looking expression

ghadi21:05:42

don't overcomplicate it, every? is lazy

donaldball21:05:03

ghadi: Wait, how is every? lazy?

ghadi21:05:24

rather, it's short-circuiting.

ghadi21:05:39

(if the pred fails)

ghadi21:05:57

despite what it sounds like

matan21:05:20

just trying to be elegant here

matan21:05:08

I think reduce is the real solution

noisesmith21:05:21

not lazy! (but short circuiting)

noisesmith21:05:33

(via reduced that is)

ghadi21:05:44

i 💙 reduce, but I promise that it would not look elegant

matan21:05:36

I wonder how come no one added the > you can write a macro to do that reply yet

mobileink21:05:22

because that would be cheating!

zylox21:05:31

wheres the fun in playing fair

matan22:05:04

kind of annoying that and is a macro, so we can't

(apply and my-list-of-booleans)
I think

mobileink22:05:20

@zylox good point. (defmacro my-and...) easy peasy!

zylox22:05:50

all the best functions are prefixed by my-

mobileink22:05:12

even better: (defmacro my-list ...) throws an exception it you give it a falsey?

matan22:05:27

beats me why and was implemented as a macro not a function

zylox22:05:41

honestly if it doesnt occasionally throw an exception based on the current millis are you even trying?

noisesmith22:05:51

@matan otherwise it can’t short circuit

mobileink22:05:51

what's the alternative?

matan22:05:58

a simple while loop can easily short-circuit

mobileink22:05:16

ao you need an "and*" macro.

noisesmith22:05:17

not preventing its args from being evaluated

jfigueroa22:05:28

maybe this could work (reduce (fn ([] false) ([x y] (and x y))) my-list-of-booleans)

noisesmith22:05:18

@jfigueroa the standard definition is that every item in a collection matches the predicate, if there are no items in the collection

noisesmith22:05:35

which means the first arity can be skipped, by starting with true as the init

noisesmith22:05:10

for short-circuiting, (reduce (fn [_ x] (if (nil? x) (reduced x) x)) true [])

noisesmith22:05:40

getting kind of ugly…

matan22:05:41

well in Scala 😛 collection.forall(identity) // and a collection collection.exists(identity) // or a collection

noisesmith22:05:55

matan: is that and / or or is it find-one / is-every? because and and or short circuit and prevent args from being evaluated

noisesmith22:05:25

(and nil (System/exit 0)) - jvm does not shut down

matan22:05:18

the latter pair of the two indeed

matan22:05:55

different semantics between the pairs indeed

matan22:05:16

callin' it a day, 2 AM

matan22:05:17

pardon my French

michaellindon22:05:29

my eyes are bleeding

matan22:05:33

guess I'm too tired to properly participate in a chat now

jfigueroa22:05:35

I think the (every? true? bools) is better 🙂

jfigueroa22:05:01

(not (some false? bools)) The truth is that I don't know which is the purpose of this 🙃 saludos!