Fork me on GitHub
#clojure
<
2015-07-22
>
jonpither07:07:20

Hi if I have a fn called foo, and then I want to memoize it, what is the conventions for naming the original fn, and the memoized fn var?

profil07:07:55

@jonpither: http://clojuredocs.org/clojure.core/memoize they use postfix "-memo" and prefix "m-" in the examples simple_smile

robert-stuttaford07:07:49

jonpither: i do a normal defn and then a separate (def memo-name (memoize that defn)) so that i can easily switch between the two during dev

robert-stuttaford07:07:14

for the cases where you know you’re good with memoized only, i’ve seen (def fn-name (memoize (fn [args] …))) too

robert-stuttaford07:07:26

like reading template from disk, that sort of thing

robert-stuttaford07:07:13

tangential, but cool: we’re using https://github.com/strongh/crache to provide core.memoize a redis backend

jonpither07:07:29

ok, my mistake was probably to hide the memoization from the caller, but having a fn like memo-foo or m-foo makes things more explicit and sounds good to me

robert-stuttaford07:07:56

yeah. as with any cache, you want a hard-refresh button simple_smile

jonpither07:07:56

@robert-stuttaford: sounds cool, we did a similar thing with memcached once

robert-stuttaford07:07:18

did it work? i looked for a memcached one but found nothing

robert-stuttaford07:07:30

we’d actually prefer that as we already have MC for Datomic

robert-stuttaford07:07:42

it’d mean one less piece of infrastructure

jonpither07:07:01

yeah it worked perfectly

jonpither07:07:06

I still have the code, let me dig it out

jonpither07:07:10

do you use the component pattern?

robert-stuttaford07:07:15

(you mean there are people who don’t? 😁)

jonpither07:07:29

I should really add it to juxt/modular, but I can give you a gist now

robert-stuttaford07:07:37

that’d be dandy, thank you!

jonpither07:07:22

this was written before the component lib was released, so we had our own protocol

jonpither07:07:07

The MailOnline used to have this public, so I don't think they will shoot me for publishing that innocuous code. It's since been converted to stuarts pattern

robert-stuttaford07:07:29

where does it become a core.cache / core.memoize backend?

robert-stuttaford07:07:35

that’s the piece i was missing

jonpither07:07:12

we didn't port it to core.cache, we just had fns (get-from-cache, and cache-miss). with (:client component), you can easily do .get, .set and .delete - you can easily take that and do a memoize thing I would think

jonpither07:07:00

we had a ns that was a custom cache thing, but yeah we prob should've ported it to something more standard

reborg08:07:56

jonpither: no we’re not going to kill you simple_smile

nblumoe10:07:23

(question moved to #C053K90BR )

cpmcdaniel15:07:39

anyone know of an ‘expect’ type of library for Clojure? Googling mostly brings up testing related libraries.

cpmcdaniel15:07:03

looks like there is expect4j

cpmcdaniel15:07:09

nah, that’s a testing framework

cpmcdaniel15:07:00

I’m talking about the classic expect library from TCL, for working with interactive shell commands

timothypratley15:07:40

oh, interesting simple_smile

cpmcdaniel15:07:46

was hoping there was something more Clojurey

timothypratley15:07:20

what usage do you have in mind? expect seems to be very shell oriented, why do you want it to be Clojurey?

cpmcdaniel15:07:50

calling out to keytool/openssl

cpmcdaniel15:07:05

both prompt for user input

cpmcdaniel15:07:01

the java API looks horrible

noisesmith15:07:03

cpmcdaniel: I have thought about how nice it would be to have a clojury expect

noisesmith15:07:03

timothypratley: I would want a clojure expect because expect is about scripting what are meant to be interactive programs, so having a good high level language that can concisely express conditions without adding unneeded complexity is a major bonus

noisesmith15:07:54

of course expect would not be needed if people did the sensible thing and wrote the non-interactive batch util first, then built the interactive tool on top of it

Lambda/Sierra15:07:09

@cpmcdaniel: Interacting with command-line processes from Java can be difficult, e.g. http://blog.headius.com/2013/06/the-pain-of-broken-subprocess.html

cpmcdaniel15:07:48

"Unfortunately, the cake is a lie."

arrdem16:07:03

bronsa: have you played with running Clojure's tests as part of the (load "/clojure.core") test?

arrdem16:07:52

seems like TEMJVM will happily emit all of Core, but some stuff breaks and sniffing out what is a pain point.

bronsa16:07:30

@arrdem: no, there is some stuff that's known to be broken by temjvm. e.g. ns-interns or one of the ns- functions, don't really remember which one

bronsa16:07:54

@arrdem: this because temjvm enforces type hints on args. will probably need to change in the future or be optional

arrdem16:07:06

oh right I remember this one.

arrdem16:07:12

the type hints in Core that are wrong.

arrdem16:07:25

or at least that you treat differently

bronsa16:07:44

well, I wouldn't say wrong -- the doc is clear that type hints are not enforced so it's technically ok to type hint with a wrong class if you never use interop on that arg

arrdem16:07:46

bronsa: ok also looks like the monitor macro doesn't emit correctly.

bronsa17:07:15

@arrdem you mean locking?

arrdem17:07:28

@bronsa: yep that's the one sorry

devlab17:07:07

@arrdem: coffee it's not soo good simple_smile

bronsa17:07:29

@arrdem: how is it broken? wrong stack depth?

arrdem17:07:05

@bronsa: I don't remember, an obvious test case I wrote yesterday didn't function as expected and it looks like I chucked it. I'll try to get you a new case and a ticket in a minute.

arrdem17:07:56

@bronsa: waiting on the next thing at work so TEMJVM is my top prio. would you rather get respond eventually emails or slack pings.

bronsa17:07:12

@arrdem I don't understand the english of your question, you might need even more coffee

arrdem17:07:53

since I don't expect you to be online and taking questions all day would you rather that I just email you crud rather than optimistically pinging you here

arrdem17:07:11

so you can ignore me at some point 😛

bronsa17:07:11

@arrdem you don't use good ol' irc anymore? anyway either is fine, I get slack notifications on my mobile when I'm offline

arrdem17:07:08

@bronsa: I mean if you wanna take over #clojure-offtopic again and relive old times 😛

ianbishop17:07:08

What's up with this:

user=> (let [{:strs [:a :b]} {":a" 1 "b" 1}] a)
1

ianbishop17:07:56

or, also strange:

user=> (let [{:strs [:a :b]} {"a" 1 "b" 1}] a)
nil

noisesmith18:07:42

ianbishop: well those strings don't match in the second example do they?

noisesmith18:07:33

ianbishop: destructuring is weird (let [{:keys {a b c d}} {:a 0 :b 1 :c 2 :d 3}] [a b c d]) => [nil nil nil nil]

noisesmith18:07:54

it doesn't really detect errors, or do sensible things when you make errors even

ianbishop18:07:05

Yeah, I just noticed the new [:a :b] destructuring. Seems like a bad idea imo. Symbol hiding + has really weird results (i.e. ":a" example)

noisesmith18:07:46

"the new [:a :b] destructuring" -> it isn't new, it's a crappy thing that works by accident

noisesmith18:07:17

there's lots of crappy things that work by accident in destructuring (or things that fail and give no indication they did so)

ianbishop18:07:45

It isn't new? I tried it in tryclj and it didn't work but it did work on a 1.7 repl. I assumed it had just been added.

noisesmith18:07:15

hmm... I don't think it's especially recent, I could be wrong though

arrdem18:07:33

@bronsa: okay I got emitter test coverage up to about 76% without doing anything too crazy. gonna need some help and odd class access cases to go above this so calling it here. found an issue with recur, but locking is behaving for me.

noisesmith18:07:52

@ianbishop: but destructuring has allowed weird unreported errors for as long as it has existed

noisesmith18:07:05

@ianbishop: my example (accidental usage of {} instead of [], leading to all keys binding to nil) has identical behavior in tryclj

ianbishop18:07:03

@noisesmith: I've seen people use the nested map destructuring and that even blew me away that it works. Craziness

noisesmith18:07:20

that, at least, is intentional and useful

ianbishop18:07:56

oh for sure, it gets pretty weird given that you can also rebind it to a different symbol. I'll probably keep mandating just keeping it simple (i.e. :keys, :strs, vector destructring etc.)

bensu20:07:23

Hi! Anybody knows how does lein repl determine the clojure version to use?

bensu20:07:04

in project.clj I specified it as 1.7.0, but the repl is using 1.6.0 and lein deps :tree shows no sign of clojure 1.6.0

arrdem20:07:38

bensu: what does *clojure-version*  evaluate to?

bensu20:07:27

in the repl? 1.6.0

arohner20:07:03

stupid question, are you running lein repl from the project dir?

bensu20:07:35

yeah, good to check anyway simple_smile

bensu20:07:07

other projects resolve to other clojure versions (the right ones)

bensu20:07:30

I'm pretty sure some dependency is pulling it in but not showing the conflict in lein deps :tree

bensu20:07:45

s/pulling it in/pulling clojure 1.6.0 in

arohner20:07:59

are you using any AOT’d libraries?

bensu20:07:19

good point. I'm not requiring any AOT myself

bensu20:07:58

Here is a gist with the project.clj and lein deps :tree https://gist.github.com/bensu/7d533b90c3e6e3907df2

bensu20:07:45

In the latest iteration I tried excluding clojure all over

rauh20:07:11

@bensu what happens if you rm -rf ~/.m2/repository/org/clojure/clojure/ and start your repl again?

bensu20:07:54

@rauh: something weid. It downloads 1.7.0, 1.7.0-RC1, and 1.4.0, and then shows me the same 1.6.0 repl

bensu20:07:16

yet in repository/org/clojure/clojure 1.6.0 is missing

rauh20:07:26

What O/S?

bensu20:07:38

ubuntu 13.10

rauh20:07:40

Can you inspect the file descriptors that the JVM is loading?

rauh20:07:56

Run htop. then filter for the java for the repl, then press l

rauh20:07:15

Or alternatively use lsof -p ...

bensu20:07:31

for some reason I'm failing to install htop

bensu20:07:39

is ps aux | grep java enough?

rauh21:07:21

do lsof -p $(pidof java)|grep "org/clojure/clojure" if you have only one java process

Lambda/Sierra21:07:23

Destructuring with keywords like (let [{:keys [:a :b]} ...] is not accidental. It was a feature introduced in Clojure 1.6: https://github.com/clojure/clojure/blob/clojure-1.6.0/changes.md#22-map-destructuring-extended-to-support-namespaced-keys

bensu21:07:37

@rauh lsof is pretty cool, thanks. the last command only shows 1.7 versions

rauh21:07:01

all from .m2 directory, yes?

rauh21:07:11

Then I don't know why you're seeing 1.6

rauh21:07:33

The lsof was just to make sure no other 1.6 jars somehow get in the JVM

bronsa21:07:05

@stuartsierra his example is using :strs, not :keys

bensu21:07:25

yes, there are no 1.6 in .m2. I think it is the one lein uses itself, but I don't know

bensu21:07:18

the problem is that I'm very lein dependent and I don't know how to start a repl without lein while populating the path with deps

bensu21:07:26

I might try with boot later

trptcolin21:07:34

@bensu: it's possible one of your dependencies did a naughty thing and AOT'ed clojure 1.6 inside the jar

rauh21:07:19

Yeah may as well just try a lein clean and a mv ~/.m2 ~/.m2-naughty and see what that does

trptcolin21:07:29

i've shell-scripted up a way to find out which, when i've run into this in the past

bensu21:07:13

I think it's lein itself, which comes with an AOT clojure

bensu21:07:25

under .lein/self-installs/

bensu21:07:47

I'll try mv

bensu21:07:06

but it will take a long times. Thanks @rauh @trptcolin

bensu21:07:11

s/times/time

bensu21:07:32

I'll come back later with what happened, but I need to give it a rest now

trptcolin21:07:06

something like for jar in $LIST_OF_JARS; do echo $jar; jar tf $jar | grep "clojure/core__init.class"

bensu21:07:23

now it's loading m2 from scratch

bensu21:07:54

didn't take that long, it's 1.6 again

bensu21:07:17

@trptcolin: I'll try your script later thanks!

trptcolin21:07:46

i'm gonna gist this up somewhere; i always end up re-doing it from scratch

rauh21:07:53

How does your ~/.lein/profile.clj look?

rauh21:07:28

Also, any lein upgrade possible?

trptcolin21:07:29

here's the real thing that'd find the issue i'm talking about if it's there: for jar in $(lein classpath | tr ':' '\n' | grep ".jar$"); do echo Checking $jar...; jar tf $jar | grep "clojure/core__init.class"; done

nberger21:07:37

DEBUG=1 lein repl shows a bit of info... and have you tried to create a new project with no dependencies, then add the ones from the project in chunks doing a binary search, to find if it's one of them?

bensu21:07:46

@rauh: upgrade didn't work 😞 and my profile.clj sans private data is in the gist

bensu21:07:31

@trptcolin: that script is genius, but it only grepped clojure 1.7

trptcolin21:07:09

@bensu: sorry - i jumped to the fancy obscure issue instead of reading your gist. you have :eval-in-leiningen true in your project.clj

trptcolin21:07:48

i believe that'll put leiningen on the bootclasspath, so lein's deps will take precedence over any of yours

rauh21:07:17

@bensu Remove your eval-in-leiningen and you'll get 1.7

bensu21:07:27

it does work.

bensu21:07:04

thanks for the help

rauh21:07:37

You're welcome

staypufd21:07:06

Hello Clojarians

magnars21:07:11

any thoughts on why name, unlike most other clojure.core functions, doesn't nil pun?

staypufd21:07:13

quick style quesiton

staypufd21:07:05

I’ve been debugging some code and put in log statements that have helped me find what’s going on. I’m thinking of leaving them in, but commented out, so if I need to later do something simliar they are already there. Thoughts on pros and cons?

noisesmith21:07:01

magnars: most of the nil punners are collection operations. There is a history in lisp of treating an empty collection as if it were nil and visa-versa.

noisesmith21:07:27

there's no such tradition for strings/numbers (unlike eg C, with empty string and 0)

staypufd21:07:07

Nil punning (mentioned at http://clojure.org) http://clojure.org/lazy#Making Clojure Lazier--The victim - nil punning

staypufd21:07:32

The victim - nil punning One of the nice things about CL's cons using nil for end-of-list is that, when coupled with nil's testability in conditionals, cons-returning functions could be used like predicates. Now only seq and next can be used in that manner - map, filter etc cannot. Note that much of the economy of the seq/nil dyad still applies, e.g. the use of when in map above.

gtrak21:07:59

it's considered idiomatic to call seq when checking for not-empty. I prefer to do that to make it obvious rather than call seq on a return value of some seq stuff and use the return value in an if directly.

gtrak21:07:51

(if-let [s (seq (some-collection-or-map-returning-operation))] (do-stuff s))

wei22:07:50

is there a form of clojure.core/walk that flattens a nested map into a sequence?

loganlinn22:07:21

@wei sequence of key pairs? does it need to preserve nested key path?

wei22:07:35

nope, it doesn’t need to keep the path

arrdem22:07:51

oh so (f {:a {:b 3 :c 4}}) = {[:a :b] 3 [:a :c] 4}?

wei22:07:24

@arrdem: sort of, but the return type should be a vector

wei22:07:55

let me rephrase, I’m confused why this doesn't work:

wei22:07:01

(clojure.walk/postwalk
 #(if (:type %) %)
 [{:fruit :apple :color :red}
  {:fruit :orange :color :orange}
  {:children [{:fruit :apple :color :green}]}])

wei22:07:00

I want this output: [{:type :apple :color :red} {:type :orang :color :orange} {:type :apple :color :green}]

wei22:07:03

but instead the output is nil

loganlinn22:07:08

how about something like (defn nested-map-seq [m] (mapcat (fn [e] (if (map? (val e)) (nested-map-seq (val e)) [e])) m))

wei22:07:15

sorry typo: I meant (if (:fruit %) %)

loganlinn22:07:40

(nested-map-seq {:a {:b {:c 2}, :d 1}, :e 1}) => ([:c 2] [:d 1] [:e 1])

loganlinn22:07:49

assuming you don’t want keys for map vals (ie :a :b) in output

wei22:07:19

nice, that works with maps but not vectors, guess I didn’t specify that it should work with any nested clojure data structure

loganlinn22:07:23

otherwise you can concat with inner call to nested-map-seq

loganlinn23:07:43

is it assumed that vectors only contain maps?

loganlinn23:07:57

Not super elegant, but seems to do the trick:

(defn flatten-map-entries [x]
  (cond
   (map? x) (mapcat (fn [[_ v :as e]]
                      (if (or (map? v) (coll? v))
                        (flatten-map-entries v)
                        [e]))
                    x)
   (coll? x) (mapcat flatten-map-entries x)
   (instance? clojure.lang.IMapEntry x) [x]
   :else nil))

(flatten-map-entries {:a {:b 1 :c [{:d :e} {:f {:g :h}} “blah”]} :i :j})
;; => ([:b 1] [:d :e] [:g :h] [:i :j])

loganlinn23:07:25

i think using clojure.walk might be wrong approach because it preserves original types

wei23:07:51

thanks @loganlinn, trying it out now