#clojure log - Aug 11 2012

The Joy of Clojure
Main Clojure site
Google Group
List of all logged dates

0:19 cemerick: xeqi: Why strange?

0:19 Yeah, I guess I should make it clear that it's a dep.

0:19 xeqi: I considered it more a dev tool

0:20 ..

0:20 cemerick: nREPL has a large footprint. :-)

0:20 The REPL you run is never part of lein's process.

0:20 xeqi: ah

0:21 sounds like a case for the :dev profile

0:21 cemerick: perhaps

0:21 xeqi: got it running on my machine btw

0:22 cemerick: I wouldn't say cljs is common enough to make available everywhere. :-)

0:22 nice!

0:23 There's a couple of one-off differences between it and the default cljs repl, but I think it's good enough for government work.

0:24 xeqi: hurray, lein-cljsbuild's browser repl works, now to see what happens when mess with piggieback

0:24 well, if I can drop the browserrepl in somehow

0:25 cemerick: after a brief look, it should be easy enough

0:26 the environment should work as-is

0:27 You may even be able to use cljs-eval directly as the eval fn

0:50 xeqi: cemerick: :)

0:50 cemerick: joy?

0:50 clojurebot: joyofclojure is http://joyofclojure.com/

0:51 xeqi: https://www.refheap.com/paste/4239

0:54 cemerick: xeqi: oh, that's sweet

0:55 * cemerick does a small dance :-)

0:55 cemerick: I didn't think it'd be that easy.

0:55 In that case, I think my job is done here. :-D

0:56 I thought I'd have to plumb some bits through to help with browser-repl too, but…damn.

0:56 now just a bit more middleware (to unify file-loading across Clojure and ClojureScript), and we'll be nearly at parity.

0:57 xeqi: there might be some more, like a pointer to -tear-down

0:57 but its functional

0:57 cemerick: xeqi: :cljs/quit will cause cljs-eval to take care of the -tear-down

0:58 xeqi: by wrapping squelch-rhino-context-error

0:58 GNOSIS-: is there anything wrong with having a transaction inside an agent?

0:58 xeqi: which doens't seem to cause any problems

0:59 cemerick: right, that won't cause any issues, even if you're not using rhino

0:59 mk: GNOSIS-: there shouldn't be, no

0:59 GNOSIS-: ah, great

0:59 I thought I read something about refs only being written at the end of an agent's execution

0:59 but I could be mistaken

1:00 mk: GNOSIS-: an agent is just another ... timestream, which is what the concurrency stuff is meant for

1:01 GNOSIS-: yes, that's right, but the opposite. When you do a transaction, if during that transaction you send to agents, the messages will be queued up until the transaction finally succeeds

1:01 cemerick: meh, I still don't grok what this stuff about static assets in browser-repl is for.

1:01 The real work will be in making it all easy to use. Should be as easy as :hooks [cemerick.piggieback.hook] or something.

1:02 xeqi: Q: are you able to start a cljs REPL, stop it, and start another in the same Clojure REPL session?

1:02 xeqi: cemerick: yeah, :cljs/quit followed by the start command + browser refresh works

1:02 cemerick: man, I get an error.

1:03 https://gist.github.com/3317393 FWIW

1:03 GNOSIS-: mk: ohhh, that makes much more sense

1:04 xeqi: cemerick: I'm guessing the static assets is just a quick way to serve an html page + complied js

1:04 rather then starting a full ring app

1:05 maybe for testing ?

1:07 cemerick: ah, you're running that from a git checkout.. I didn't try that

1:07 mk: GNOSIS-: that's also the reason that agent queues are described as "potentially not in order - you can only depend on sends from a given thread being in order"

1:07 cemerick: xeqi: Yes, though it happens for me everywhere; git, maven dep, whatever.

1:07 xeqi: but I was able to restart the browser repl from within the same nrepl

1:08 cemerick: dnolen couldn't duplicate, and it sounds like you can't either, so…

1:10 xeqi: I'm running OpenJDK Runtime Environment (IcedTea7 2.1.1pre) (7~u3-2.1.1~pre1-1ubuntu3) on 64bit incase it helps

1:11 cemerick: I'm on stock OS X 1.6.0_33 *shrug*

1:11 I'm not motivated to ramp up an ubuntu dev environment to track it down. :-)

1:17 xeqi: blah, nrepl.el gives me an error when trying to start the browser repl

1:18 nm, needed to remember to use lein from git

1:21 mk: how does (hash) differ from hashCode?

1:22 xeqi: cemerick: wee, emacs -> nrepl.el -> piggieback/cljs-repl -> browser -> noir -> browser -> alert box

1:23 cemerick: I'm confused by the multiple appearances of "browser", but: sweet!

1:23 xeqi: normal server response there

1:24 cemerick: well, browser -> noir -> browser -> alert box is just a web app

1:24 xeqi: made from xhr invoked from browser repl

1:24 cemerick: oh, ok :-)

1:24 remember, I'm a noob :-P

1:25 xeqi: mk: looks like null hashes to 0, https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Util.java#L113

1:27 mk: xeqi: ah, thanks

1:28 Cr8: `(map hash [0 nil "" {} #{}])

1:28 xeqi: &(map hash [0 nil "" {} #{}])

1:28 Cr8: ah

1:29 or not

1:29 mk: cemerick: don't worry, we were all noobs at one point. Just keep at it

1:29 xeqi: ah, lazybots missign

1:29 ,(map hash [0 nil "" {} #{}])

1:29 clojurebot: (0 0 0 0 0)

1:29 mk: if you're having trouble try picking up one of the clojure books, I hear they're great

1:29 cemerick: mk: which one do you recommend?

1:30 mk: the latest one's pretty good, forgot what it was called though

1:30 cemerick: mk: you mean http://clojurebook.com?

1:32 mk: yeah that one

1:33 pyykkis: cemerick: joy of clojure is an another great one

1:33 cemerick: yeah, I've got both of 'em :-)

1:33 Cr8: hey, i contributed a very minor correction to that clojurebook one

1:33 xeqi: heh

1:33 Cr8: I tweeted it to some Chas fellow.

1:34 cemerick: mk, pyykkis: sorry, I just had to do it ;-)

1:34 mk: cemerick: ;)

1:34 cemerick: It's always so hard to know who's trolling who.

1:35 Cr8: thanks for that :-)

1:36 pyykkis: cemerick: hah, I just read your survay on state of clj :p

1:36 * Cr8 is the resident Clojurian at Couchbase

1:36 cemerick: xeqi: And thanks for verifying the browser-repl; will add that to the docs, just as soon as I figure it out myself. :-)

1:37 ah-ha! Cool

1:37 xeqi: np, I find the browser-repl one of the best things out of cljs, so had to jump and see if it worked

1:37 pyykkis: no wonder your nick felt familiar.. :P

1:37 * cemerick is stealthy

1:38 cemerick: And tired. g'night all

3:50 AustinYun: anyone have any good tips on how to idiomatically solve this short problem?

3:50 https://github.com/austinyun/challenges/blob/master/array-iteration-interview-problem/PROBLEM.md

3:51 i have a clojure version mostly done but i'm not sure about the right way to traverse an array from the right

3:51 to avoid calling "reverse" on an array twice

3:51 https://github.com/austinyun/challenges/blob/master/array-iteration-interview-problem/add1.clj

3:55 hyPiRion: I'll have a look at it

3:55 AustinYun: its just a little thing i saw on hacker news last week or so

3:56 an interview problem a guy likes to ask, and his observation that ruby people tend to solve it by calling Array.reverse twice

3:57 summary: write a function add1 that takes an array, a value, and a magic number "n"

3:57 add 1 to each element in the array if it matches the value passed as a parameter, but only N times if N is positive

3:58 and if N is negative, do the same, but starting from the end of the array

3:58 i thought it was interesting because i can't think of how to do it purely functionally (every solution i saw was a variant of C style loops)

4:01 ill admit that i spent a good 8 hours writing my javascript version, lol

4:03 hyPiRion: Hm.

4:03 clojurebot: It's greek to me.

4:07 hyPiRion: yeah, it's hard to do this functionally.

4:07 :p

4:08 AustinYun: my js solution (which my clojure is mostly a translation of) is to make a closure over the "count" idea from n

4:11 hyPiRion: It's kind of messy, because you have so much data into that single n.

4:11 AustinYun: even if you unroll it all into the "n is a negative number" scenario

4:12 the idea of incrementing values from the end of an array, but only a certain number of times, seems difficult to deal with

4:13 n = 0 is trivial -- just (map incrementer input-array) where incrementer could just be an anonymous function (if (= x y) (inc y) y))

4:14 ill have to ask some haskell people tomorrow, lol

4:15 but i have a really hard time following haskell code

4:15 too bad i missed cemerick

4:31 hyPiRion: https://www.refheap.com/paste/4244 is my result

4:32 an ugly pile of code, though.

4:46 rod_: hi - i'm trying to find a clojure event graphing server i read about ages ago (like statsd) but can't remember the name now - gah! can anyone help?

4:51 DaoWen: AustinYun: why not just use the loop macro?

4:51 beffbernard: rod_: http://aphyr.github.com/riemann/ ?

5:02 rod_: beffbernard: YES!!!!!! thanks very much, will bookmark now.

5:02 :D

5:03 DaoWen: AustinYun: it looks like you're actually using vectors instead of arrays in your sample code. if that's the case, you can call rseq on the vector, which returns a "reversed" sequence from a vector or sorted-map *in constant time* (it doesn't actually reverse it, but rather provides a reversed view of the sequence)

5:09 * talios goes crazy and publishes a frege-maven-plugin - now to learn me some frege.

5:22 _ulises: morning all

5:23 talios: 'lo

5:28 daniel__1: good morniiin

5:44 mindbender1: what's the modern way of managing external clojurescript libraries?

5:47 talios: how are you building your project? lein? If I was using maven I'd just store them in a jar and use the remote-resources-plugin and use dependencies.

5:48 I should really look at clojurescript before talking about it tho ;)

7:26 sayyestolife: Hey, I'm wondering if there is some other nicer way to structure the following code? http://pastebin.com/AUsMDYcQ

7:35 hyPiRion: sayyestolife: Have you seen the -> and ->> macros?

7:36 sayyestolife: I've used -> a bit yes

7:36 problem is that I have several varying (in value) parameters

7:37 I've only used it in the case where I have functions of 1-arity (and thus have done like (-> var fn fn2 fn3))

7:39 _ato: sayyestolife: you can go: (-> world (set-at x y :player) (set-at (inc x) y :player) (set-at ...) ...)

7:40 hyPiRion: ^

7:40 https://www.refheap.com/paste/4245 is the result I get

7:40 sayyestolife: _ato: I can? How can it know that world is suppose to be the first argument?

7:40 _ato: -> threads the first argument

7:40 ->> threads the last argument

7:40 sayyestolife: oh, kind of like currying almost?

7:40 hyPiRion: sayyestolife: Try to look at the code after macroexpand and clojure.walk/macroexpand-all

7:41 sayyestolife: will do, cheers

7:42 hyPiRion: sayyestolife: Anyway, I think a more elegant solution would be like this: https://www.refheap.com/paste/4246

7:42 Just throwing my 50 cents out there.

7:44 sayyestolife: I suppose, but that got me thinking of an even better way, cheers again

7:46 hyPiRion: sayyestolife: That's awesome! Good luck onwards with the code :)

7:47 sayyestolife: thanks, I just love this language, even though what I write is crap compared to most on people on 4clojure and such, it is still so much more beautiful than what I write in other languages

7:52 wmealing: sayyestolife, i sometimes feel the same way

8:13 can you "require" a java library as a shortened name

8:13 so that i dont need to spell the whole path out every time ?

8:30 _ulises: wmealing: you can :import classes in your ns

9:41 mindbender1: technomancy: I remember seeing a link to a style guide on leiningen page but I'm having trouble locating it.. mind giving me a hand?

9:44 ok found it, that was on swank-clojure (;

9:57 Cheiron: what are the equivalent of assoc-in and update-in for transient data structure?

10:00 cshell: what do you mean by transient?

10:01 Cheiron: transient data structure in clojure is the counterpart of immutable one

10:02 modifiable data structure

10:04 cshell: oh

10:04 assoc in and update in allow you to specify a series of keys for nested associated datastructures

10:05 for mutable datastructures, these semantics would still apply, they would just have the side effect of modifying the target structure

10:05 Cheiron: actually both aren't working

10:06 java.lang.ClassCastException: clojure.lang.PersistentArrayMap$TransientArrayMap cannot be cast to clojure.lang.Associative

10:06 cshell: they only work on associative structures (ie maps)

10:06 not arrays

10:06 oops, you have an array map

10:06 Cheiron: i created (def t (transient {}))

10:08 cshell: ,(assoc-in {:a "a"} [:a] "b")

10:09 clojurebot: {:a "b"}

10:09 cshell: it works for the non-transitive

10:09 xeqi: Cheiron: assoc!, dissoc! and conj! work, but I don't see equivalents to update-in/assoc-in

10:11 Cheiron: while profiling my clojure code that calls update-in, i noted that the most created instances are Cons

10:11 xeqi: you'd have to translate those yourself I think -- http://clojuredocs.org/clojure_core/clojure.core/update-in#source

10:11 Cheiron: but afaik, clojure don't embrace Cons concept since it has seq concept

10:12 and why the most created objects are char[] ? according to Visual VM

10:13 cshell: cheiron

10:14 cheiron: you can try to use (get-in ) to get what you want to modify and then do a assoc!

10:14 goodieboy: is there a nifty, functional way to produce a lazy seq with this pattern? [[0 0] [1 0] [2 0] [0 1] [1 1] [2 1]]

10:15 casion: goodieboy: there'd be plenty of ways to do it, depending on how the pattern extends beyond that

10:15 Cheiron: cshell: I see, thanks

10:16 goodieboy: casion: OK, well what I'm trying to do is take a string like "ABC DEF GHI" and pull extract the first letter from each word, at the end repeat, but then the second word, repeat etc.

10:17 so in the example, "ABC DEF GHI" become "ADGBEH"

10:19 i was thinking about using loop, but that feels very imperative. I'd like to be able to "take" from this lazy seq, n items for example

10:21 anyway, i thought if i could come up with a lazy seq of indices, then i could use those to pull out the needed characters

10:21 casion: goodieboy: sec

10:22 goodieboy: np :)

10:22 xeqi: &(clojure.string/join (apply mapcat vector (clojure.string/split "ABC DEF GHI" #" ")))

10:22 lazybot: ⇒ "ADGBEHCFI"

10:23 xeqi: goodieboy: ^

10:25 goodieboy: xeqi: beautiful. I need to pull that apart and understand what's happening. Thanks for that.

10:25 daniel__1: anyone use Guard to auto run their tests? i would like to see an example Guardfile

10:25 gfredericks: &(clojure.string/join (apply str (clojure.string/split "ABC DEF GHI" #" ")))

10:25 lazybot: ⇒ "ABCDEFGHI"

10:26 gfredericks: goodieboy: ^ no reason for the apply mapcat vector

10:26 &(apply str (clojure.string/split "ABC DEF GHI" #" "))

10:26 lazybot: ⇒ "ABCDEFGHI"

10:26 gfredericks: while we're at it no reason for the string/join either

10:26 * gfredericks didn't actually read the question yet

10:27 * casion sigh

10:27 casion: well, I cant use clojure overnight for some reason

10:28 that was a badly formed sentence if there ever was one

10:28 goodieboy: gfredericks: :) oh, well i don't want to just glue it all together in-order, the output is a little different than that

10:28 * gfredericks retracts everything he's ever said

10:28 goodieboy: haha

10:28 xeqi: hmm, didn't know str did that

10:29 goodieboy: i need to spend an hour playing with mapcat

10:29 gfredericks: it's just (apply concat (map f coll))

10:30 casion: humph. the namespace in my repl was wiped by sleeping my laptop

10:30 how weird

10:30 no wonders nothing worked

10:31 gfredericks: clojure forgets everything at 3am every night

10:31 casion: gfredericks: it would appear so

10:31 goodieboy: ,(apply mapcat vector ["ABC" "DEF" "GHI"])

10:31 gfredericks: it forces you to not make assumptions about code longevity

10:31 clojurebot: (\A \D \G \B \E ...)

10:31 goodieboy: ,(apply concat (map vector ["ABC" "DEF" "GHI"]))

10:31 clojurebot: ("ABC" "DEF" "GHI")

10:32 goodieboy: hmm

10:32 gfredericks: ,(mapcat vector ["ABC" "DEF" "GHI"])

10:32 clojurebot: ("ABC" "DEF" "GHI")

10:32 gfredericks: that's the one I was thinking of

10:32 I don't think I've ever applied mapcat before

10:32 goodieboy: oh i see the diff now, yeah it's apply on mapcat

10:35 casion: xeqi: your solution doesnt produce a lazy sequence though?

10:36 xeqi: casion: cause string/join uses it all

10:36 if he just wants the seperate characters it is lazy

10:36 casion: ah

10:38 goodieboy: xeqi casion: how about making ["ABC" "DEF" "GHI" "J"] produce "ADGJBEHCFI" ? :)

10:51 firesofmay: is it possible for me to use Selenium Grid 2 with clj-webdriver?

10:52 goodieboy: totally struggling here.. how would i implement something that worked like this: (take 4 (xyz 2)) => '((0 0) (0 1) (1 0) (1 1)) where "2" is the dimension of the inner seq?

10:53 i smell iterate, but not behaving the way i thought it did

10:59 DaoWen: goodieboy: what does the "xyz" stand for?

11:02 goodieboy: DaoWen: sorry, that's a bad example. I guess what I'm trying to show with that is, i want the dimensions to be controlled by arguments. So the xyz function would some how produce a sequence of numbers, where the values would increment

11:02 DaoWen: goodieboy: https://github.com/clojure/math.combinatorics

11:03 I think selections would do what you need

11:03 goodieboy: DaoWen: wow, nice. That looks very much like what i have in mind.

11:04 DaoWen: goodieboy: (selections [0 1] 2) => ((0 0) (0 1) (1 0) (1 1))

11:04 goodieboy: DaoWen: ha yes! awesome, i'll try it out now

11:05 DaoWen: (selections (range 10) 2) counts from 0 to 99

11:06 xeqi: firesofmay: I don't see RemoteWebDriver in the list of keywords, so I don't think support is built in

11:06 DaoWen: goodieboy: all of the functions in that library return answers in lexicographic order

11:07 xeqi: * in the keyword -> driver map

11:09 goodieboy: DaoWen: ok thanks. Hey, would you happen to know the maven name/group and version for that lib?

11:09 i can't find it

11:10 DaoWen: goodieboy: org.clojure/math.combinatorics "0.0.3"

11:10 goodieboy: DaoWen: thanks!

11:10 DaoWen: that's what I have in my project.clj

11:10 goodieboy: excellent, that worked

11:20 DaoWen: thanks again! That's exactly what I was looking for :)

11:21 DaoWen: goodieboy: glad I could help :)

11:37 firesofmay: okay xeqi thanks

11:50 beffbernard: Is there an equivalent in swank/slime to clean -> build ?

12:43 nsxt: i stumbled across project euler and decided to take a crack at #18 (http://projecteuler.net/problem=18). i figured i'd take a bottom-up approach, which "collapses" each row into the one above by taking the max of the summation of adjacent cells. (that probably sounds cryptic, but if you're following along with the sample problem on the site, the penultimate row would contain 125 164 102 95 etc..) problem is, i'm still a noob and

12:44 metellus: nsxt: your line cut off at "problem is, i'm still a noob and"

12:45 nsxt: metellus: thanks - "problem is, i'm still a noob and i don't know how to model this succinctly (or at all...)"

12:47 metellus: nsxt: I don't know how to help, but maybe now someone else can

12:49 llasram`: Oh wow, redesign on the Project Euler page

12:49 nsxt: metellus: i think i'll diagram a shorter problem to clarify what it is i'm trying to achieve

12:50 llasram: nsxt: I'm having trouble teasing your question out of your text :-)

12:52 nsxt: llasram: yeah, sorry... give me one second and i'll provide you with a better diagram/explanation

12:52 yoklov: nsxt: you might want to try a greedy approach

12:53 instead of a bottom-up one, but that's just a thought.

12:53 llasram: nsxt: As a side note, I learned Clojure by doing Project Euler problems, and I think it's a good approach. Maybe 4clojure would be even better for this, gave me a chance to wrap my head into the functional mindset for "real" problems w/o needing to tackle the stack of libraries and JVM interop you need for most real-world applications

12:53 metellus: I think it'd be pretty easy to make a triangle where the greedy approach fails

12:54 I like nsxt's bottom-up solution... I just don't know how to model it in Clojure

12:55 yoklov: oh, yeah, you're right

12:56 llasram: nsxt: Oh, I see what you're suggesting. I actually remember this one, because I did the same approach, only went down instead of up for some reason, so then needed to max the resulting set. Collapsing upwards and getting the final answer at the top is totally the way to go

12:57 nsxt: yoklov: the greedy approach, if i think we're on the same page, will take something like billions of years to calculate (if you move up to 100 rows)

12:57 yoklov: err, it shouldn't

12:57 nsxt: llasram: yes, so sorry for my convoluted explanation. here's a refheap which describes it better: https://www.refheap.com/paste/4247

12:57 yoklov: but it might get the wrong answer, now that i think more.

12:58 nsxt: yoklov: what does the greedy approach entail?

12:59 metellus: the greedy approach would be to start at the top and always choose the max of the two options below

12:59 it's called "greedy" because it decides based on short term gains only

12:59 yoklov: or keep a priority queue, and each time a node becomes visible push it on the queue, keeping the nodes updated

12:59 nsxt: metellus: so top-down. right, it wouldn't take billions of years to calculate, sorry yoklov.

13:01 llasram: nsxt: So which is the part that you're having trouble thinking how to represent in Clojure?

13:01 yoklov: but the priority queue isn't the most idiomatic for clojure. i think its what i did when i did these in scheme though.

13:02 nsxt: llasram: it's just the collapsing process. i've destructured the list so that i can get the last two "rows", but i don't know how to craft the function to do what i want.

13:03 llasram: Well, you want to reduce a sequence to a single value, so probably (drum roll) `reduce` :-)

13:04 If you have the rows ordered from bottom to top, then using `reduce` the 'state' you're building is the last collapsed result, and you'll get the next row up with each iteration

13:05 nsxt: llasram: right, i guess the most difficulty is in crafting the lambda to pass to reduce

13:06 llasram: and it's probably more conceptual than anything - a lot of the collections on 4clojure are identical in length, whereas here the collection lengths differ by one

13:06 llasram: Oh, you may which to check out `partition`

13:07 nsxt: thank you, am checking now

13:08 aha, so i can pad it out then

13:08 antoineB: hello is there a problem with closure and the map function?

13:09 llasram: nsxt: Well,

13:09 antoineB: i get an IndexOfBoundException

13:09 llasram: nsxt: I'm not sure padding is correct. I was thinking more repeating

13:09 Er, via the implications of the `step` argument

13:09 antoineB: i would like use : (map #(my-fun %1 next-level)

13:10 and : (defn my-fun (text & level) ...)

13:10 nsxt: llasram: mind if i pm you?

13:10 antoineB: the error come from those two line

13:10 *lines

13:11 * (map #(my-fun %1 next-level) a-list)

13:11 next-level lis a local binding

13:11 *is a local binding

13:12 llasram: antoineB: Well, for one thing, that `defn` line can't be right -- function arguments need to be specified as vector, not a list

13:12 dbushenko: ckirkendall, hi

13:12 antoineB: llasram: i just miss-spell, its a vector in my code

13:12 dbushenko: how is it going with enfocus issue #22 ?

13:17 llasram: antoineB: Not enough there to really say much on... Can you post a gist which reproduces your problem?

13:18 antoineB: i will

13:19 https://gist.github.com/3325837

13:25 TimMc: technomancy: So what's the deal with kibit 0.0.4 and lein? Have you figured it out yet?

13:26 danielglauser: Has anyone worked with clj-oauth2 to connect to Salesforce? https://github.com/DerGuteMoritz/clj-oauth2

13:34 antoineB: llasram: any ideas?

13:35 llasram: antoineB: in `exceed-splitter`, > vs >=

13:35 off-by-one -- you pass in a (0-based) index then compare it to a count

13:37 antoineB: llasram: thanks that was just a silly error

13:37 but println don't flush?

13:40 DaoWen: nsxt: I've been doing project euler problems in Clojure as well. I have my solution for problem 18 here if you're interested: https://github.com/DaoWen/euler/blob/master/src/project_euler/problems_020.clj

13:41 nsxt: oops, I didn't include the line number https://github.com/DaoWen/euler/blob/master/src/project_euler/problems_020.clj#L240

13:45 nsxt: I did top-down rather than bottom-up, but at least it shows that all the calculations can be done succinctly

13:50 antoineB: is there a function to print "outside" of #(...) function used in the map function?

13:50 example if i use: (map #(do (println "a") 1) [1 2 3])

13:51 i get: ("a" 1 "a" 1 "a" 1) as output

13:51 where i expect "a" "a" "a" (1 1 1)

13:55 DaoWen: antoineB: does this work? (doall (map #(do (println "a") %) [1 2 3]))

13:55 that worked in my repl

13:56 the reason the prints are interspersed throughout the result is because the map function is lazy

13:56 mattmoss: ,(map println [1 2 3])

13:56 clojurebot: (1

13:56 2

13:56 3

13:56 nil nil nil)

13:57 DaoWen: it only does the work of actually computing an element once it's forced to do so

13:57 ,(doall (map #(do (println "a") %) [1 2 3]))

13:57 clojurebot: a

13:57 a

13:57 a

13:57 (1 2 3)

13:57 mattmoss: ignore my example... I incorrectly read yours.

13:58 DaoWen: mattmoss: thanks, for some reason I didn't think the bot would handle the printlns correctly

13:58 good to know that it does

14:00 antoineB: the reason that adding (doall ) around the whole expression fixes the printing issue is that (doall ) forces the entire mapped sequence to be realized before passing back the result, so all of the (println "a") calls happen before the repl gets back the result and displays it

14:00 dbushenko: ,(let [m (map #(do (println "a") %) [1 2 3])] m)

14:00 clojurebot: (a

14:00 a

14:00 a

14:00 1 2 3)

14:04 mindbender1: where is the clojure.instant namespace in clojurescript located?

14:05 jam`: I guess you need clojure 1.4 if you're getting cljs complaining about missing clojure.instant

14:07 mjg123: Hi - Is there a way in clojurescript to handle javascript objects with circular references inside?

14:07 mindbender1: jam: ok I think so, my project.clj has 1.3

14:07 mjg123: js->clj does a stack overflow, and JSON/stringify won't touch it either

14:09 jam`: mindbender1: yep, should be, I had a similar problem

14:12 antoineB: DaoWen: that works

14:12 DaoWen: antoineB: great!

14:13 antoineB: thank you

14:16 yoklov: what does the recursive? argument mean in read?

14:17 oh, that it's happening within another call to read, got it.

14:50 skaurus: Hi! I'm a Clojure novice and have a simple question: why this snippet doesn't work as expected (i.e. doesnt return 0): (defn func ( [param] (def param (- param 1)) param )) (func 1)

14:51 danielglauser: skaurus: I don't believe you are defining the function correctly

14:51 gfredericks: skaurus: you want let rather than a nested def; def creates globals

14:52 (defn func [param] (let [param (- param 1)] param)) (func 1)

14:53 skaurus: gfredericks: I tried that, it returns 0 too...

14:53 gfredericks: let me check my typing, maybe there is subtle typo

14:53 danielglauser: (defn fund [param] (let [new-val (- param 1)] new-val)

14:53 gfredericks: skaurus: you want it to return 0, right?

14:54 danielglauser: ,(defn func [param] (let [new-val (- param 1)] new-val)

14:54 clojurebot: #<ExecutionException java.util.concurrent.ExecutionException: java.lang.RuntimeException: EOF while reading>

14:54 skaurus: gfredericks: oh, I meant it returns 1 too

14:54 But I have a excessive brackets in my defn! :)

14:54 metellus: you're missing a paren, but I don't know that clojurebot lets you defn anyway

14:54 ,(defn func [param] (let [new-val (- param 1)] new-val))

14:54 clojurebot: #<Exception java.lang.Exception: SANBOX DENIED>

14:55 danielglauser: :)

14:55 gfredericks: skaurus: it returns 0 for me

14:55 metellus: ((fn [param] (let [new-val (- param 1)] new-val)) 1)

14:55 ,((fn [param] (let [new-val (- param 1)] new-val)) 1)

14:55 clojurebot: 0

14:57 skaurus: Thanks so far!! But then I trying to create multifn like that: ( defn func ([] (func 1)) ([p] (let [p (- p 1)]) p) ) And (func 1) returns 1 too. Now I MUST have that brackets that was excessive, right?

14:57 mk: the bot should probably trigger any time it sees an expression that compiles

14:58 metellus: skaurus: is there any particular reason that you're using p for both the param and the new value you're computing?

14:58 gfredericks: mk: you can trigger in the middle of a message ##(list :like :this)

14:58 lazybot: ⇒ (:like :this)

14:59 mk: has anyone ever said something that starts with (..symbol and ends with ), but it wasn't just a case of accidentally omitting ,?

14:59 metellus: parentheticals are pretty common on irc

14:59 (maybe not in this channel, though)

15:00 ((see what I mean?))

15:00 mk: gfredericks: yeah, I recall that. I mean that it just seems pointless to even have a ,

15:00 metellus: the parentheticals you provide wouldn't compile :)

15:00 gfredericks: but the bot would have to try it nonetheless

15:01 if I put a + in the middle of a sentence, that's a compilable expression

15:01 ,+

15:01 clojurebot: #<core$_PLUS_ clojure.core$_PLUS_@2f71e573>

15:01 skaurus: metellus: maybe that's my background, but I'm trying to avoid declaring of new unnecessary variables. Also in the end I'm trying to pass a "accumulator" var to my func; that func should add some values to it and calls itself recursevly with new value of "accumulator". After some number of calls it finishes and returns final value of "accumulator".

15:01 mk: gfredericks: don't print if it doesn't compile, unless preceded by ,?

15:02 gfredericks: mk: + compiles

15:02 metellus: skaurus: using def or let like that is very uncommon for clojure

15:02 and for functional programming in general

15:02 mk: gfredericks: if someone says just +, I sort of expect the bot to respond

15:03 gfredericks: mk: what about in the middle of a sentence like yours there?

15:04 mk: gfredericks: it would amuse me. But for longer messages, it might check for brackets or for the use of unknown symbols

15:05 skaurus: metellus: so what would be a idiomatic way to accumulate values from recursive function calls? Maybe I should define global var and add to it (or rather redefine it) in each iteration?

15:05 metellus: pass the accumulator as a parameter to the function

15:06 skaurus: I'm trying exactly that, but in multidef as in example above I can't change argument value for some reason.

15:07 "... ( defn func ([] (func 1)) ([p] (let [p (- p 1)]) p) ) And (func 1) returns 1"

15:07 metellus: (defn factorial ([n] (factorial n 1)) ([n acc] (* n (factorial (- n 1) acc))))

15:07 with a base case in there when n = 1

15:07 err, my example was terrible and should be ignored

15:08 skaurus: thank you! Right now I'm inexpectedly should leave but I'll try to understand what's going on using that example.

15:08 oh)

15:08 hiredman: so was skaurus's so it comes out in the wash

15:09 mk: skaurus: what do you mean by accumulator? The recursive function should never change the value of something passed to it

15:09 metellus: writing on an irc input line is hard

15:14 skaurus: https://www.refheap.com/paste/4251 here's an example that actually works. I don't promise that it's the best way to do it, but it works.

15:18 skaurus: but in general, with Clojure you should prefer to declare new variables when necessary instead of changing the values of existing ones

15:19 Chousuke: or you structure your code so that you don't need variables :P

15:29 cshell: Does anyone know of any geospatial clustering libraries for clojure?

15:35 mk: cshell: java libraries are compatible

15:41 skaurus: metellus: Thanks!

15:42 mk: well, doesn't reduce does exactly that?

15:44 mk: skaurus: no, reduce produces a new value

15:45 skaurus: mk: ok. I still wrapping my head around immutable variables :)

15:46 cshell: mk, that's what I was thinking - thanks!

15:48 mk: skaurus: they aren't variables. They're values. You might be imagining a single "thing" passing through some sort of function, and coming out differently. That's not quite how it works

15:48 cshell: np

15:49 skaurus: if you look at that refheap link, the "acc" is entirely different on each recursion. It isn't like an object that you add 10 to, and then give back.

15:50 raek: skaurus: you might find my answer to this so question interesting. the question is about immutable variables and loops. http://stackoverflow.com/questions/8540855/setf-in-clojure/8564082#8564082

15:51 skaurus: mk: that makes more sense now, thanks)

15:53 raek: it looks like what I need. Hard to understand all semantic from first sight, but it is ok. Thanks!

15:53 mk: skaurus: if you're unsure about anything, feel free to ask in here. It takes a bit of time and several tries to finally get your head around, but that's fine

15:58 Nikelandjelo: Is there a way to check if code is executing inside repl?

16:02 I'm writing some GUI and want frame to close and exit from jvm if it's running as script and only close when it's inside repl. So I need to determine somehow whether current environment is repl or not.

16:13 xeqi: Nikelandjelo: DISPOSE_ON_CLOSE not working for that?

16:15 Nikelandjelo: xeqi: It doesn't kill jvm, only closes frame. But if I run app standalone (without repl) I want it to quit. It seems I can use *file* to determine if it's repl.

16:15 xeqi: hmm, guess there are some threads still running

16:16 wonder if thats a clojure artifact

16:16 Nikelandjelo: It's the same in java

16:16 If you use DISPOSE_ON_CLOSE jvm is not killed

16:16 lynaghk: dnolen: can core.match be used to compile decision trees that execute all matching branches, or is it optimized to find the first matching branch only?

16:17 xeqi: Nikelandjelo: if you use DISPOSE_ON_CLOSe the jvm stays alive if there are other windows or non-daemon threads

16:17 otherwise it will exit cleanly

16:18 lynaghk: dnolen: I'm thinking about pubsub in cljs. Goog's implementation is exact string matching only. Things like redis allow "/approx/*/matches/*" and I'm wondering how performant we could make something like content-based matching. E.g., (subscribe {:x x :msg "ABC"} ...)

16:18 xeqi: I would think that would work for clojure, but the agent threadpool might be keeping it alive :/

16:19 haven't done swing since moving to clojure so not certain there

16:19 but it seems like you found a work around thats good for your situation?

16:20 Nikelandjelo: I haven't tried yet. Want to check about DISPOSE_ON_CLOSE in java now :)

16:22 dnolen: lynaghk: core.match doesn't find all matches

16:23 lynaghk: dnolen: okay, that's what I thought, thanks.

16:23 dnolen: lynaghk: I've been thinking along the lines of where you're going tho ... could be interesting.

16:23 lynaghk: dnolen: yeah. I've gotten myself tangled up in the auto-watcher magic of my Reflex library a few times, so I'm looking around to other approaches

16:25 dnolen: the FRP thread on the dev list has pretty much entirely left my area of understanding; I'm trying to stay grounded and just tally up specific use-cases and try different approaches.

16:26 dnolen: anyway, it seems like the only reason not to use structured pattern matching on message content over string-based topics is performance, no?

16:26 dnolen: lynaghk: I think pubsub is a good place to start.

16:27 lynaghk: I really dislike string based matching

16:27 lynaghk: any pubsub matching should be based on data IMO.

16:28 xeqi: Nikelandjelo: http://docs.oracle.com/javase/6/docs/api/java/awt/doc-files/AWTThreadIssues.html - relevant auto shutdown docs, might be understandable if you come from java

16:38 Nikelandjelo: xeqi: thanks, interesting article

16:41 kaoD_: hi

16:41 are there any opensource projects using robert hooke I can check?

16:41 (besides leiningen)

16:43 emezeske: kaoD_: lein-cljsbuild uses robert hooke a little bit

16:43 kaoD_: thanks emezeske

16:43 emezeske: kaoD_: I don't know if it's a great example though :)

16:44 kaoD_: I'm curious: order of evaluation is completely random or does it follow a pattern?

16:45 xeqi: first arg -> last arg

16:45 kaoD_: xeqi: I mean in robert hooke's hooks

16:46 (inter-namespaces especially)

16:46 I guess it depends on namespace loading order which is random without heavy hacking or dirty tricks, right?

16:47 emezeske: kaoD_: I believe it is true that there's no easy way to control the order that the hooks are applied

16:47 kaoD_: I am not an expert on hooke though

16:53 nkoza3: How do you use simultaneously :keys and :or in map destructuring? This doesn't seems to work: (let [{:keys [a b] :or {:b 3}} {:a 1}] [a b]) ;=> [1 nil] but expected [1 3]

16:54 gfredericks: ,(let [{:keys [a b] :or {b 3}} {:a 1}] [a b])

16:54 clojurebot: [1 3]

16:54 gfredericks: thar it is

16:55 nkoza3: ahh thanks

17:14 Cheiron: Hi, how fnil is different from partial method?

17:14 partial *function

17:15 gfredericks: ,(doc fnil)

17:15 clojurebot: "([f x] [f x y] [f x y z]); Takes a function f, and returns a function that calls f, replacing a nil first argument to f with the supplied value x. Higher arity versions can replace arguments in the second and third positions (y, z). Note that the function f can take any number of arguments, not just the one(s) being nil-patched."

17:15 gfredericks: ,(let [f (fn [a] (+ a 5)), g (fnil f 10)] (g))

17:15 clojurebot: #<ArityException clojure.lang.ArityException: Wrong number of args (0) passed to: core$fnil$fn>

17:15 gfredericks: ,(let [f (fn [a] (+ a 5)), g (fnil f 10)] (g nil))

17:15 clojurebot: 15

17:16 gfredericks: Cheiron: it lets you specify default arguments, in case the ones gives are nil

17:16 whereas partial lets you specify the arguments such that they don't need to be passed to the returned function

17:18 Cheiron: Oh, eye c

17:18 gfredericks: ,(let [+ (apply fnil + (range))] (+ 7 8 nil 3 nil nil nil nil))

17:18 &(let [+ (apply fnil + (range 50))] (+ 7 8 nil 3 nil nil nil nil))

17:18 lazybot: clojure.lang.ArityException: Wrong number of args (21) passed to: core$fnil

17:18 clojurebot: Execution Timed Out

17:19 gfredericks: wait does fnil only work up to arity 3?

17:19 ,(fnil + 1 2 3 4)

17:19 clojurebot: #<ArityException clojure.lang.ArityException: Wrong number of args (5) passed to: core$fnil>

17:19 gfredericks: ,(fnil + 1 2 3 )

17:19 clojurebot: #<core$fnil$fn__3361 clojure.core$fnil$fn__3361@d5e391d>

17:19 gfredericks: that's so weird

17:19 Cheiron: http://clojuredocs.org/clojure_core/clojure.core/fnil

17:20 it looks yes, max arity is three

17:20 gfredericks: I guess that lets it return a fixed-arity function :/

17:23 xeqi: &(doc partial)

17:23 lazybot: ⇒ "([f arg1] [f arg1 arg2] [f arg1 arg2 arg3] [f arg1 arg2 arg3 & more]); Takes a function f and fewer than the normal arguments to f, and returns a fn that takes a variable number of additional args. When called, the returned function calls f with args + additional args."

17:23 xeqi: checking if partial was limited ^

17:23 Raynes: Who was it who was doing the array iteration problem thingy last night?

17:24 AustinYun: https://www.refheap.com/paste/4252 is a fun little solution I hacked together.

17:25 Not saying it is idiomatic, but it popped into my head when I saw the problem.

17:25 Aso, darn it. That should be highlighted as Clojure. refheap.el, why have you forsaken me?

17:26 * Raynes sets the language manually.

17:27 Nikelandjelo: Does anybody know some interesting simulation (e.g. some game) where atoms (refs, agents) are very useful?

17:27 xeqi: Raynes: add nrepl-clojure-mode to the supported modes list?

17:28 Raynes: xeqi: That's probably the problem. Didn't even occur to me.

17:28 xeqi: ~ants

17:28 clojurebot: ants is http://clojure.googlegroups.com/web/ants.clj

17:29 xeqi: heh, its not there

17:29 nkoza3: so, swank-clojure is still ahead of nrepl.el ? which one do you use?

17:29 xeqi: clojurebot: forget ants is http://clojure.googlegroups.com/web/ants.clj

17:29 clojurebot: 'Sea, mhuise.

17:30 Raynes: nkoza3: I'd recommend using nrepl.el.

17:31 xeqi: nkoza3: I use nrepl.el. I think the main feature difference is swank has a way to do breakpoints

17:31 Raynes: It is easier to use and is only prohibitive if you actually need things from swank that it doesn't have which is unlikely.

17:31 nkoza3: ok, I will try it, thanks

17:32 xeqi: nrepl.el has all the developers behind it, so I expect it will overtake swank as better for clojure shortly

17:34 llasram: Raynes: I really depend on those congratulatory start-up messages when connecting to a swank instance. How soon until nrepl.el gets feature-parity there?

17:35 Raynes: llasram: It has it already.

17:35 llasram: Awesome! Time to switch!

17:35 oskarth: This seems very verbose to me: (defn rand-in-range [range] (+ (* (+ (- (last range) (first range)) 1) (rand 1)) (first range)))) Ideas for how to make it shorter?

17:35 xeqi: I don't think it mentions lemondor fame anymore though

17:37 llasram: I didn't really get that one. I guess lemondor was famous among CLers while it was an active blog? Or was it more than that?

17:37 xeqi: basically that

17:37 Nikelandjelo: oskarth: you need to get real number between (first range) and (last range) ?

17:38 oskarth: Nikelandjelo: yes

17:38 xeqi: &(doc rand)

17:38 lazybot: ⇒ "([] [n]); Returns a random floating point number between 0 (inclusive) and n (default 1) (exclusive)."

17:39 xeqi: aww, I was hoping it would just take the boundaries

17:39 oskarth: it doesn't, unfortunately

17:39 dnolen: oskarth: if range is actually a range and is large that seems like a bad approach.

17:40 oskarth: yes

17:40 err so it's just small arrays [a b]

17:40 Nikelandjelo: (defn rand-in-range [[a b]]

17:40 (+ a (rand (- b a))))

17:40 sorry

17:41 xeqi: &(rand 0)

17:41 lazybot: ⇒ 0.0

17:42 Raynes: Does anybody think that Clojure should have a rand-long function? Since longs are default now, seems weird to only have rand-int.

17:42 Not that it's hard to type (long (rand ..))

17:42 gfredericks: ,(type (rand-int 20))

17:42 Raynes: But it isn't hard to type (int (rand ..)) either, so..

17:42 clojurebot: java.lang.Integer

17:43 Raynes: &(rand-int 999999999999999999)

17:43 lazybot: java.lang.IllegalArgumentException: Value out of range for int: 924440368767550720

17:43 Raynes: I run into that all the time.

17:43 gfredericks: weerd; it never ocurred to me that the "-int" might be referring to the java type

17:43 Raynes: gfredericks: The implementation is literally (int (rand n)) iirc.

17:44 llasram: Yeah, that's weird. Why even bother having it?

17:44 * gfredericks is in favor of deprecation

17:45 oskarth: oh nvm btw, was a mixup

17:45 Raynes: llasram, gfredericks: Agreed, but if it is out of the question, adding a rand-long seems appropriate.

17:45 oskarth: misread range input

17:46 gfredericks: Raynes: well I meant both

17:46 add rand-long, deprecate rand-int

17:47 also add rand-ratio just for kicks

17:47 Raynes: Hah

17:47 schaefer: any core.logic expertise in the house?

17:47 gfredericks: schaefer: yes

17:47 and

17:47 ~anyone

17:47 clojurebot: Just a heads up, you're more likely to get some help if you ask the question you really want the answer to, instead of "does anyone ..."

17:48 schaefer: thanks, clojurebot :|

17:48 gfredericks: though I understand the point that you don't want to waste your time typing out the question :)

17:48 Cheiron: clojurebot: besame mucho

17:48 clojurebot: It's greek to me.

17:48 casion: maybe he just wanted to know if anyone had experience.. and nothing more

17:48 what then huh? what then?

17:49 gfredericks: clojurebot always simplificates nuanced issues

17:49 schaefer: i'm putting together a zork GPS app using core.logic. i've got relations for direct-path between two rooms. generally, i assume that a direct-paths between two rooms is bi-directional but, i've got a blocked relation that indicates certain directions from particular rooms are blocked

17:49 my question is: i want to write a goal that lists all directions NOT blocked in a room

17:50 gfredericks: you can certainly do it non-relationally

17:50 schaefer: i can't wrap my head around how to do a exclusion

17:50 gfredericks: that's where exclusions normally lead if you can't re-express it in some positive way

17:50 schaefer: i'll start with a non-relational approach, though part of this is a learning exercise (not just about zork!) so if there is a relational solution, i'd love to learn it

17:51 gfredricks: i see. how would i do this non-relationally?

17:51 gfredericks: (conda ((blocked a b) fail) ((can-go a b)))

17:51 that kind of syntax I think

17:52 schaefer: thanks. makes sense. let me give that a try

17:57 ok, so here's my not-blocked goal:

17:57 (defn not-blocked [room direction]

17:57 (conda

17:57 [(blocked room direction)

17:57 fail]

17:57 [(fresh [ending-room]

17:57 (direct-path room ending-room direction))]))

17:57 this returns success:

17:57 (with-facts [[direct-path [['a 'b :n]]]

17:57 [blocked [['a :e]

17:57 ['a :w]]]]

17:57 (run 5 [q]

17:57 (not-blocked 'a :n)))

17:58 but, i'm surprised that running (not-blocked 'a q) fails

17:59 gfredericks: I bet this is why non-relationalness is unideal :)

17:59 schaefer: ah :)

18:00 gfredericks: I believe when you use a non-relational goal, all the arguments should be ground

18:00 else you will get unexpected results

18:00 if you add (membero q [:n :e :w :s]) to the top of your program, does that make it work?

18:00 schaefer: i was hoping that if i through in (membero direction directions) into the goal definition, it would magically work out

18:00 ha, see above :)

18:01 gfredericks: so did it? :)

18:01 schaefer: nope

18:01 same result

18:01 gfredericks: booo

18:02 schaefer: yeah, i desperately want to change the not-blocked goal into a function that iterates over [:n :e :s :w] and test each one separately

18:02 but, i promised myself to use core.logic exclusively

18:03 gfredericks: schaefer: can you paste your whole bit of code on refheap so I can play with it?

18:03 schaefer: sure. what the url of refheap?

18:03 nm, got it

18:04 https://www.refheap.com/paste/4253

18:04 dnolen: schaefer: I think you can probably solve this one with disequality ...

18:04 schaefer: go on... :)

18:04 dnolen: (!= path ['a :e])

18:05 schaefer: i don't follow

18:06 gfredericks: that would require an enumeration of the blockings outside of core.logic I think

18:06 rather than a blocked goal

18:06 schaefer: yeah, that's what i'm trying to avoid. i want to assume a bi-direction graph unless explicitly blocked

18:06 i think this would be pretty straightforward otherwise

18:06 gfredericks: well you have to enumerate it anyways using defrel/fact

18:07 so it's just a different mechanism. You'd loopish over your blockings vector and use disequality on each element

18:07 dnolen: gfredericks: he's already specifying the blocked paths outside via facts.

18:08 as a rel

18:08 gfredericks: dnolen: yep

18:08 schaefer: you mean, this:

18:08 (defn not-blocked [room direction]

18:08 (membero direction directions)

18:08 (fresh [a-room a-direction]

18:08 (blocked a-room a-direction)

18:08 (!= a-room room)

18:08 (!= a-direction direction)))

18:08 maybe i don't need the membero

18:09 gfredericks: no not that

18:09 dnolen: schaefer: try to not paste in channel :)

18:09 schaefer: sorry :)

18:09 gfredericks: schaefer: assume you have (def blockings [['a :e] ['a :s] ...])

18:10 schaefer: k

18:10 gfredericks: then you can define a (not-membero) goal that uses !=

18:10 so then (not-membero [room direction] blockings)

18:10 schaefer: ah, so the trick is to treat blockins as a vector rather than a relation...

18:11 i'll give that a shot. curious though: would the domain stuff in ckanren make this easier? i briefly toyed with it but i don't understand it enough

18:12 gfredericks: afaik that stuff is only numeric; so I don't see how

18:12 dnolen: schaefer: I'd have to think about that. but in this case I think disequality will do want you want and it'll be relational.

18:13 schaefer: cool. i'm updating my code now. i'll let you know in a few minutes

18:13 thanks for the pointer

18:17 gfredericks: schaefer: (membero q directions) makes it succeed for me

18:18 schaefer: added above (not-blocked 'a q)

18:18 schaefer: can you paste your solution into refheap? i'm obviously doing something wrong

18:19 also, i'm a bit surprised by the results of my not-membero. https://www.refheap.com/paste/4254

18:19 gfredericks: https://www.refheap.com/paste/4255

18:20 ah yeah your not-membero does all the !='s independently

18:20 so what it really asserts is "There's something in v that is not u"

18:21 (defne not-membero [x coll] ([_ []]) ([_ [y . ys]] (!= x y) (not-membero x ys)))

18:22 schaefer: ok. i'm going to have to brush up on my defne and dotted-list notation. i don't grok what this is doing

18:22 my two week prolog class was lo so many years ago

18:23 so, the first clause says that anything cons'd to the empty list will succeed

18:23 dnolen: schaefer: gfredericks goal ensures that x won't unify with anything in coll.

18:23 gfredericks: (defn not-membero [x coll] (conde ((emptyo coll)) ((fresh [y ys] (firsto coll y) (resto coll ys) (!= x y) (not-membero x ys)))))

18:23 schaefer: ^ same thing without defne

18:24 schaefer: thanks, that's hugely useful

18:24 dnolen: schaefer: your goal only guarantees that x won't unify with *something* in coll which is not what you want.

18:24 schaefer: gotcha

18:25 gfredericks: schaefer: so yours only fails if v is all u's

18:25 and succeeds once for everything in v that is not a u

18:26 schaefer: gfredericks: to jump back to your solution. you provided (membero q directions) in the run. i'm surprised that the first membero in not-blocked goal doesn't accomplish the same thing

18:26 i'm sure this is because i'm thinking of the goal more like a subroutine but i'm having trouble internalizing what's going on

18:27 gfredericks: schaefer: ah ha -- that's a syntax issue

18:27 that line has no effect

18:28 schaefer: oh! do i need an all?

18:28 gfredericks: yeps

18:28 schaefer: i've been bitten by that before

18:28 i'm writing a defgoal macro to ensure that i don't get hit by that again

18:28 gfredericks: the core.logic relations generally have no side effects, so if you (defn [...] a b c) then a and b won't do anything

18:29 schaefer: sure. so, the good news is that i was thinking of things correctly but i hadn't defined a real goal (at least, not the goal i thought i was defining)

18:29 gfredericks: right

18:30 schaefer: ah ha! it's so satisfying to see the little (:n)

18:31 gfredericks: what a weird emoticon

18:31 schaefer: :) thanks folks

18:34 nkoza3: where the println output goes when in clojure-nrepl-mode?

18:35 Raynes: What is the *nrepl* buffer, Alex?

18:38 nkoza3: if I type (println "hello|) in the *nrepl* buffer, then the "hello" is printed on that buffer, but if I do C-M-x in a (println "hello") on the file buffer then the return value shows in the minibuffer but I don't know where the println output goes

18:40 Raynes: Yeah, that is weird.

18:40 Might want to open an issue about that at https://github.com/kingtim/nrepl.el

18:50 gfredericks: slime is the same way isn't it?

18:57 nkoza3: i don't know, i'm just a newbie :)

19:11 cshell: Is there any clojure based k-means clustering libraries? I know I could try to use Mahout, but it seems like a Clojure native could benefit from the parallelism of Clojure

19:43 zakwilson: I'm starting to think that making vars non-dynamic by default was a Bad Thing. Being able to dynamically rebind somebody else's function that's called in a third party's library code has been incredibly useful to me on occasion.

19:44 Raynes: Isn't that like monkey patching?

19:44 gfredericks: is var dynamicity mutable?

19:45 Raynes: IIRC, yes.

19:45 gfredericks: (defmacro monkey-patch ...)

19:46 Raynes: (defmacro please-god-no ...)

19:46 gfredericks: Raynes: clojure has to say yes to things

19:46 Raynes: Steve has Spoken.

19:46 zakwilson: That's exactly like monkey patching, except a little more controlled since binding itself is lexically scoped.

19:47 And I actually did write a macro in CL called "monkeypatch". It made normal functions in to multimethods.

19:47 gfredericks: either I totally misunderstand lexical scope or that's exactly wrong

19:47 Raynes: You're like the expert on doing crazy things with functions and vars.

19:47 Someone is wrong on the internet, hold my calls.

19:48 AustinYun: Raynes: i'll take a look in a minute, thanks

19:48 gfredericks: Raynes: hey you started by disagreeing with monkeypatching

19:49 Raynes: I purposely avoided disagreeing with it and just asked if I was correct that what he described was monkey patching.

19:49 I'm cleverer than I look.

19:49 emezeske: I really like the Yegge "Say Yes" attitude, but I also think it's incredibly unhelpful to say "Yes, here is how you do an imperitive for loop with mutability in Clojure" instead of "You probably want to use this thing called reduce, here are the docs"

19:49 gfredericks: you said "(defmacro please-god-no ...)"

19:49 which contains "no"

19:49 Raynes: Okay, I slipped up.

19:50 nkoza3: the semantics of calling a function using a Var are as if the Var is lookuped each time... but how is implemented? when you redefine the Var all the call places are somehow mutated to point to the new function so the Var isn't really lookuped in each call?

19:59 zakwilson: Common Lisp provides exactly the functionality I described with multimethods (:before, :after, :around methods, to be specific) - and yes, I misused "lexical" before. What I really meant is that binding has the structure of a with- macro in that it only applies to things that happen inside it.

19:59 But ultimately, I *am* advocating something like monkeypatching. The tar and feathers are over there if you need them -->

20:18 dnolen: zakwilson: is that what http://github.com/technomancy/robert-hooke/ is for?

20:18 isn't I mean.

20:21 gfredericks: as long as he doesn't have a need for thread-locality

20:21 clojurebot: the world <reply>what the world needs is more higher order functions

20:27 zakwilson: Yes, dnolen, that may be exactly what I wanted.

20:28 antares_: Raynes: heya

20:47 zakwilson: I think the thing I didn't know about was alter-var-root. I guess I don't need to miss dynamic-by-default.

20:47 gfredericks: zakwilson: with-redefs is the root equivalent to binding

20:48 the difference is that binding's effects are thread-local

20:52 zakwilson: Right. I don't actually want thread-locality.

20:54 What I do want is to be able to hook in to anybody else's code and bend it to my will regardless of the consequences. Looks like this does exactly that... now what happens when I try to hook core functions and do funny things to them?

20:54 cshell: shouldn't make a difference

20:55 that's it's a core function you're hooking, that is

20:55 gfredericks: unless it's one of the inlined arithmetic functions

20:57 zakwilson: I remember trying to do something related in Common Lisp and having it blow up when I used it on +. This was quite some time ago and I may well have been doing it wrong.

20:58 gfredericks: ,(with-redefs [+ -] (+ 2 3))

20:58 clojurebot: 5

20:58 gfredericks: ,(with-redefs [cons -] (cons 2 3))

20:58 clojurebot: -1

20:59 amalloy: you can't (usefully) redef functions that are inlined

20:59 ,(with-redefs [+ -] ((identity +) 2 3))

20:59 clojurebot: -1

21:00 gfredericks: ,(with-redefs [+ -] (#'+ 2 3))

21:00 clojurebot: -1

21:00 gfredericks: (defmacro without-redefs [pairs & forms] (cons 'do forms))

21:02 cshell: what's the name of the function that applies a function to the first elements of each collection passed in and then the second, etc

21:02 Raynes: antares_: hi

21:03 cshell: like (something + [1 2] [3 4]) => [4 6]

21:03 antares_: Raynes: I cannot reproduce your issue with Ring not being loaded. I don't think it has anything to do with Monger.

21:03 Raynes: antares_: I'm not sure what I'm doing wrong.

21:03 llasram: cshell: map

21:04 antares_: Raynes: can you be using noir checkouts by any chance?

21:04 cshell: llasram: ah, that's it - thanks -I've only used it with one collection before

21:04 Raynes: antares_: No.

21:05 antares_: Raynes: hm, I don't know then, but somehow you don't have ring on the classpath

21:05 Raynes: antares_: It works fine before your commit.

21:05 *shrug*

21:05 antares_: Raynes: but monger never depended on ring

21:06 Raynes: can you try nuking your local repository?

21:06 Raynes: antares_: https://www.refheap.com/paste/cc26e83b8d9469bc111298fa7

21:06 Output of `lein classpath`

21:06 ring is on there.

21:08 antares_: https://github.com/ring-clojure/ring/blob/master/ring-core/src/ring/middleware/session/store.clj#L4

21:08 the protocol hasn't changed

21:10 Raynes: antares_: FWIW, I'm not blaming you.

21:11 antares_: Raynes: sure, I am just very confused how monger can affect ring loading

21:11 and I don't want refheap to be stuck forever on a beta version

21:19 Raynes: after nuking ~/.m2/repository, refheap still compiles for me

21:19 Raynes: antares_: After nuking it, refheap still doesn't compile for me. :\

21:20 antares_: Raynes: does REPL start? can you try requiring ring's session store ns?

21:23 Raynes: antares_: Can't find it there either.

21:25 antares_: Well, I can require it.

21:25 antares_: But it gives me the same error at startup.

21:27 antares_: I understand

21:28 Raynes: antares_: I can't access the SessionStore class.

21:29 Ah, yeah I can.

21:29 If I type the right class. ;)

21:29 antares_: Yeah, I'm stumped, man.

21:29 I feel like blaming Leiningen.

21:29 antares_: Raynes: I think it is something about the way I use protocols then

21:30 Raynes: You use them in such a way that they magically don't work on OS X? :p

21:31 antares_: Raynes: that they may depend on load ordering

21:33 Raynes: can you try monger-1.2.0-SNAPSHOT? just pushed

21:33 Raynes: Sure. One moment.

21:33 emezeske: Raynes: Hey, regarding refh cljs stuffs

21:33 Raynes: What happens if you rename the file core.cljs instead of core.clj?

21:34 Raynes: Oh man.

21:34 emezeske: Did I name it clj?

21:34 If that's the problem, I'm going to kill myself.

21:34 antares_: No change.

21:34 emezeske: Hmm, a simple self-flagellation would suffice; I don't know if you have to go all the way to full suicide

21:36 Raynes: emezeske: That fixes it. I'm sorry for bothering you.

21:37 emezeske: emezeske: It is warning me that you should be using leiningen.core.main/about instead of numeric exit values, and then says cljsbuild failed.

21:37 (but it doesn't fail)

21:38 emezeske: Raynes: Is that lein 2?

21:38 Raynes: emezeske: Yes.

21:38 emezeske: I haven't tested it against lein 2 in a while, it's constantly changing

21:38 I probably need to do a test+fix run sometime soon

21:38 Raynes: emezeske: Yeah, this wont work at all in the official lein2 release.

21:39 emezeske: Maybe I can look at that tomorrow

21:40 * emezeske goes off to dinner.

21:41 Raynes: dnolen: ping

21:43 dnolen: Raynes: pong

21:44 Raynes: dnolen: Whenever I compile cljs targeting node, running the output prints "The "sys" module is now called "util". It should have a similar interface.". Looks like sys is util in later versions of node.

21:44 Any thoughts on that?

21:44 dnolen: Raynes: patch?

21:44 :)

21:45 Raynes: seems like a one two liner to me.

21:45 Raynes: dnolen: https://groups.google.com/d/topic/clojure-dev/2kNEWsztyqw/discussion

21:45 Pretty sure I can't legally patch anything.

21:46 At least according to what one of the Stus told me.

21:46 It's probably to be a while before I can get that sorted out.

21:46 I can see if amalloy will patch it for me though, if you're busy.

21:46 dnolen: oh that stinks, feel free to open a ticket - I'll take a look at it.

21:47 Raynes: Alright

21:49 dnolen: http://dev.clojure.org/jira/browse/CLJS-354 <-- Pretty sure I can legally create issues under an assumed name! :p

21:52 gfredericks: dnolen: is the fd stuff in core.logic supposed to work with e.g. (interval -100 100)?

22:00 oh nm, my previously failing case seems to be working now

22:02 dnolen: gfredericks: negative values are not supported in any way.

22:02 gfredericks: it may work, but I make no promises :)

22:02 gfredericks: oh ha; good to know

22:03 dnolen: can you point me to any resources that explain why the ckanren approach is limited to finite domains and can't be easily extended to e.g. all integers?

22:05 dnolen: Raynes: http://github.com/clojure/clojurescript/commit/67e120c53774cae1a71b0a021fcdd5e3f8f888ab, let me know if that doesn't work for you.

22:06 gfredericks: it's just more work, the solver has to be extended to handle it.

22:06 Raynes: dnolen: I have no idea how to run clojurescript without cljsbuild, which pulls it itself.

22:06 :p

22:06 I'm pretty sure that's all that was necessary though.

22:06 dnolen: gfredericks: we're quickly approaching the point where enhancements will have to come from the community :)

22:06 Raynes: just use lein checkouts

22:07 gfredericks: dnolen: I'm happy to contribute, I just don't find understanding the codebase to be easy

22:07 dnolen: Raynes: mkdir checkouts, :extra-classpath-dirs in your project.clj

22:07 gfredericks: always feel free to ask questions.

22:10 gfredericks: dnolen: since reading up on why lazy-seqs don't work, I've wondered how much simpler the codebase might be if it instead used an enhanced lazy seq (e.g., (defprotocol ITickableSeq (tick "Returns true if a new item is available" [self])))

22:10 dnolen: gfredericks: I doubt it would be much simpler. The goal stuff is like 100 lines.

22:11 Scriptor: gfredericks: link to why lazy-seqs don't work?

22:11 gfredericks: okay; just a thought

22:11 Scriptor: one sec

22:12 $google clojure the reasoned scheduler

22:12 lazybot: [Clojure and me » The Reasoned Scheduler] http://clj-me.cgrand.net/2012/01/30/the-reasoned-scheduler/

22:12 gfredericks: Scriptor: ^

22:12 Scriptor: h, thanks

22:12 *ah

22:12 dnolen: gfredericks: the reason core.logic is so much larger than miniKanren is nearly all performance related - unification for all the Clojure data types is tons of code.

22:13 gfredericks: but it's not really necessary to look at unification bits, they all look the same.

22:13 gfredericks: dnolen: I think it's more the monadish stuff I get bogged down in rather than the LOC; I don't at all mean that as a criticism since I haven't built my own in any other manner :)

22:14 * gfredericks didn't mean to imply that he's built his own logic engine at all

22:14 dnolen: gfredericks: the monadish stuff is actually pretty simple.

22:14 Raynes: dnolen: Either I don't know how to do this or checkouts don't work with things that don't have a project.clj.

22:14 dnolen: Raynes: yeah you need project.clj

22:14 Raynes: Which makes sense, of course.

22:15 dnolen: gfredericks: (== q 1) just returns a closure, it's effectively (fn [a] (unify a q 1))

22:15 gfredericks: all goals are exactly the same.

22:15 so a miniKanren just threads the substitution map thorugh closures.

22:16 gfredericks: maybe it would make more sense to me trying to dig in it since reading the scheduler blog post; prior to that I expected that (conde (a) (b)) would strictly alternate between a and b

22:16 dnolen: if you never use conde, it just threading a value through a bunch of functions.

22:16 gfredericks: but now I believe it depends on exactly what a and b are doing how frequently each one emits a success

22:17 dnolen: gfredericks: the alternating behavior of conde is a distraction, all conde does is take single substitution and return multiple ones.

22:17 (bind (fn [a] ...) a) -> (a0 a1) is what conde does.

22:18 bind just pushes the substitution into each closure to run it and it gets either nil, a substitution oor multilpe subsitutions.

22:18 clojurebot: I'm sorry, dnolen. I'm afraid I can't do that.

22:18 * gfredericks hmms

22:19 dnolen: at the end it simple looks up the value of q (the query variable) in each substition and outputs that.

22:19 gfredericks: right; that part seems pretty simple to me :)

22:20 dnolen: again the alternating stuff takes a while to sort out, but at a high level you don't really care.

22:20 it's just a giant mapcat

22:21 Raynes: dnolen: Is there any sort of release schedule for cljs yet?

22:21 dnolen: Raynes: not really.

22:21 Raynes: Fixing the output manually take like a millisecond, so it isn't a big deal.

22:22 gfredericks: dnolen: thanks for the overview

22:25 dnolen: gfredericks: http://gist.github.com/3329111

22:26 gfredericks: it's pretty easy to inspect what's going on. note that those anon fns must return a

22:26 gfredericks: returning nil will signal failure.

22:26 gfredericks: right

22:26 dnolen: gfredericks: there's really nothing more to it as far as core miniKanren.

22:28 gfredericks: dnolen: the high level behavior makes sense to me. It's when I try to make sense of code like `(fn [~a] (-inc (mplus* ~@(bind-conde-clauses a clauses)))) and I start expanding things and there are four functions all nested in eachother and jumping through the codebase to see where everything goes makes a big tangle

22:29 dnolen: gfredericks: so if you really want to know I can explain mplus and inc.

22:29 gfredericks: mplus will return a lazy list like thing

22:29 (mplus (bind some-goal subst) (fn thunk [] ...))

22:30 so that's a left and right branch of a search tree right there.

22:30 how do you get it bounce between the two?

22:31 gfredericks: is inc analagous to the ITickableSeq I brought up earlier?

22:31 dnolen: easy make the left branch return a thunk

22:31 if you get a thunk, flip the branches

22:31 gfredericks: ah ha

22:31 dnolen: (mplus (fn thunk [] ...) inc-thunk)

22:32 gfredericks: it should also flip if it gets a substitution back, right?

22:32 to avoid starving the other?

22:32 dnolen: no a substition means you have a *choice*

22:33 so it'll look like this (choice found-something (fn [] (mplus ...)))

22:33 because conde's actually expand into:

22:33 (mplus (bind ...) (fn [] (mplus (bind ...) (fn [] ...))))

22:34 gfrederick: https://github.com/clojure/core.logic/blob/master/src/main/clojure/clojure/core/logic.clj#L1103

22:34 gfredericks: so a choice holds a new substitution _and_ the remaining lazy stream?

22:34 dnolen: that's precisely what Substitution IMPlus looks like

22:34 gfredericks: yep.

22:35 gfredericks: mplus is just a way to move around while looks for real substitutions

22:35 s/looks/looking

22:36 Raynes: dnolen: Thanks for patching that for me btw. Sorry I couldn't do it myself.

22:36 dnolen: gfredericks: and here's the flipping on thunks http://github.com/clojure/core.logic/blob/master/src/main/clojure/clojure/core/logic.clj#L1891

22:36 Raynes: np

22:37 gfredericks: dnolen: what about take?

22:38 dnolen: gfredericks: take is just a trampoline that extracts choices

22:39 gfredericks: http://github.com/clojure/core.logic/blob/master/src/main/clojure/clojure/core/logic.clj#L1855

22:40 gfredericks: okay, so take is for reifying the stuff into an actual seq?

22:40 dnolen: gfredericks: yes, the output that you actually see.

22:40 run*, run N is just sugar over take.

22:45 tlowrimore: I'm rather new to Clojure (currently a full-time Ruby dev), and I'm curious to know whether there are any best practices when it comes to creating and managing a database schemas. Something like migrations in ActiveRecord?

22:45 Raynes: dnolen: Any reason something like this isn't in cljs? https://gist.github.com/3153856

22:46 gfredericks: dnolen: that was all very helpful.

22:47 cshell: tlowrimore: Isn't this something specific to relational databases and not different in Clojure vs Ruby?

22:48 dnolen: gfredericks: another cool tidbit, why conda / condu work the way they do.

22:48 gfredericks: it all about how they deal with Choice.

22:48 gfrederick: https://github.com/clojure/core.logic/blob/master/src/main/clojure/clojure/core/logic.clj#L2240, conda actually works on the entire choice

22:49 gfredericks: condu https://github.com/clojure/core.logic/blob/master/src/main/clojure/clojure/core/logic.clj#L2262, ignores the remainder of the stream.

22:49 tlowrimore: cshell: if I understand your question correctly, I'm referring to the scripting of the db setup--at the application layer--rather than say, db specific DDL.

22:50 I see that Drift aims to provide part of this functionality, but it appears as a basic interface rather than a full-blown impl.

22:51 cshell: ah, yeah that would have to be something in a library/app level - not in Clojure itself

22:51 Why not use Mongo so you don't have to worry about schema migration?

22:51 tlowrimore: yes, sorry for my ambiguity.

22:51 Mongo doesn't really suit my need for this project.

22:52 cshell: If you're using clojure you can put clojure maps directly into mongo without any transformation - it makes it really nice

22:52 tlowrimore: How does that work for report-style querying?

22:52 gfredericks: dnolen: I stared at that for a minute and now I can imagine how it might make sense :)

22:53 cshell: something like (mongo/insert! :my-collection {:attr1 val2 :attr2 val2}

22:53 tlowrimore: By using RDBMS, I'm hoping to index the shit out of the data.

22:53 dnolen: gfredericks: a Choice might result in many possible answers.

22:53 cshell: you can do indexes in Mongo

22:53 tlowrimore: ...very read-heavy application

22:53 cshell: it's just a different way of thinking about data

22:54 dnolen: gfredericks: condu just extracts the first one, conda doesn't

22:55 gfredericks: dnolen: those lines are in the context of the head of a cond[au] clause already succeeding?

22:55 dnolen: gfredericks: if you have choice it must have.

22:55 gfredericks: gotcha

22:56 dnolen: gfredericks: any implementation of any protocol on Choice means yes we found something that works.

22:58 gfredericks: dnolen: and the fact that "no further lines are tried" in either case is reflected in the fact that both of them ignore the 'c' argument

22:59 dnolen: gfredericks: yep, that's the delay for the other clauses

23:01 gfredericks: it's why on nil we force c.

23:01 gfredericks: the use of delay there I find surprising, since I figured that's something that -inc accomplishes

23:02 dnolen: gfredericks: -inc means something very specific - it's about scheduling

23:02 gfredericks: we don't need that here.

23:02 gfredericks: gotcha

23:05 dnolen: gfredericks: note that there's no interleaving for condu and conda unlike conde. so a bad branch can get you when you use them unlike conde.

23:05 gfredericks: so that's something that could (possibly?) be improved - I just adopted the miniKanren approach here.

23:06 gfredericks: but perhaps not ... since if you using conda/u you probably want something deterministic.

23:06 gfredericks: yeah I was just going through that thought process myself

23:07 if (conda ((run-forever)) (succeed)), the fact that the second line succeeds doesn't help until you've figured out the first line

23:08 dnolen: gfredericks: so cKanren is just a layer ontop of all this that doesn't really touch the core of any off this stuff.

23:09 gfredericks: we have a constraint store which maps vars -> constraints.

23:09 gfredericks: constraints simply run when a vars value changes and refines the vars value.

23:10 the bulk of the new code is that we have 3 different domain reps

23:10 FiniteDomain for small sets of pos integers. Intervals for larger sets and efficient interval math.

23:10 and MultiIntervalFD for those cases where ranges get sliced out of IntervalFD

23:11 gfredericks: what effect does (+fd a b c) have when none are ground?

23:11 dnolen: gfredericks: there's a protocol IRunnable, default is that if none of the vars have domains, constraint doesn't run.

23:12 gfredericks: +fd in general can't run until a b c all have domains.

23:12 gfredericks: but if all have domains but still not ground?

23:12 dnolen: gfredericks: I'm working on some stuff where +fd can run even if *c* doesn't have one, so that we can write less tedious code.

23:12 gfredericks: I just can't think of how to describe +fd in terms of intervals

23:12 dnolen: gfredericks: a var is ground if it has a domain in the core.logic implementation

23:13 gfredericks: oh okay, so walking with the var leads to a domain object

23:13 so we say (infd a b c (interval 0 1000000)) then (+fd a b c); what does that do to the domains?

23:13 dnolen: (+fd (interval 1 2) (inteval 2 3) q), q clearly is (interval 3 5)

23:14 gfredericks: does the +fd start enumerating all triples?

23:14 dnolen: gfredericks: no

23:14 gfredericks: in that case that's not enough information to do anything

23:14 gfredericks: so it literally has no effect?

23:14 or it might have an effect later if we learn more?

23:15 dnolen: it will intersection (interval 0 1000000) w/ (interval 0 2000000)

23:15 which results in ....

23:15 (interval 0 1000000)

23:15 for c

23:16 gfredericks: at some point this turns into enumeration...that happens within take?

23:16 dnolen: gfredericks: later if a or b or c gets more specific values then the constraint will run again.

23:16 gfredericks: okay so the +fd stores something in the constraints store

23:16 dnolen: gfredericks: only at the end right before reification, IForceAns is the protocols.

23:16 gfredericks: enumerating possibilities is last resort basically

23:17 gfredericks: all the constraints go into the constraint store.

23:21 gfredericks: oh -- was there any performance reason to use FDs in the sudoku code over #(membero % [1 2 3 4 5 6 7 8 9]) and a != -based distincto?

23:21 sudoku itself has nothing to do with numbers of course

23:21 dnolen: gfredericks: big performance reasons.

23:21 gfredericks: so distinctfd must do magical stuff compared to !=

23:22 dnolen: gfredericks: distinctfd can work on directly on Clojure sets w/o triggering search.

23:22 gfredericks: membero == serach

23:22 gfredericks: interesting

23:22 dnolen: gfredericks: distincfd basically adds a constraint on each var

23:23 when a var gets single value, its constraint checks that no other var has it, and then removes it from all the others vars domains, which is fast just a (disj ...). then it remove itself from the constraint store.

23:25 gfredericks: the big idea here is that backtracking, searching is something to be avoided. constraints lets us shrink the space we have to search very quickly.

23:28 gfredericks: right

23:28 dnolen: gfrederick: https://github.com/clojure/core.logic/blob/master/src/main/clojure/clojure/core/logic.clj#L3476

23:29 gfredericks: each distinctfd constraint knows all the other vars that are involved.

23:29 gfredericks: n* is the list of known values, y* is vars with domains (not yet single values)

23:30 (process-dom d (difference (walk s d) x)) ... that's the var looping and removing it's value from the other vars domains.

23:32 gfredericks: the explanation makes sense...the code less so; but I haven't been thinking about this constraint stuff for nearly as long as I have the core minikanren, so I suppose that's to be expected

23:33 dnolen: gfredericks: makes sense. constraints all use reify, since we want them to be fns, but we also need to be able reflect on certain properties.

23:34 gfredericks: when I look at this to try to get a feel for it, I see four functions named -distinctfdc and -distinctfd and distinctfdc and distinctfd...

23:34 my code tends to look like this too whenever I'm doing something complicated :)

23:34 dnolen: gfredericks: all goals are wrapped in cgoal. cgoal does the meta stuff that every constraint needs to do.

23:34 is it runnable? add it to the store etc.

23:35 foo is the wrapped constraint. fooc is the real constraint.

23:35 gfredericks: ah ha

23:35 dnolen: gfredericks: there reason there are two distinctfdc is that the list of vars can be fresh.

23:36 so it's just a expressiveness thing.

23:36 gfredericks: relevant? checks if a constraint could possibly have something useful to say in the future?

23:36 dnolen: soon as distinctfdc gets a ground list of vars, it creates -distinctfdc for all of them.

23:37 gfredericks: relevant? is the test to see if the constraint should be kicked out of the store.

23:38 gfredericks: we don't want to rerun constraints that won't give us new information

23:39 gfredericks: right

23:39 alright I think I need to let all this bake for a bit

23:40 dnolen: gfredericks: heh, lot of info I know :) but if you've got some more questions let me know.

23:40 gfredericks: dnolen: I will, thanks much; I'm looking forward to hacking on it

23:43 dnolen: gfredericks: I look forward to it as well. I'm open to ideas how to make this all more clear.

23:44 gfredericks: that includes var renaming patches, comment patches for subtle code etc. clearly the cKanren stuff is more up in the air ATM, but the core miniKanren is not going to change in the near future.

23:48 gfredericks: dnolen: all the constraint stuff we just talked about is straight from ckanren?

23:49 dnolen: gfredericks: no, I took a lot of liberties - cKanren Scheme is very new so there a lot of perf design decisions I made that are specific to core.logic

23:49 gfredericks: okay

23:49 dnolen: gfredericks: there also abstraction stuff, like runnable? relevant?

23:50 in the Scheme, every constraint hard coded that stuff into it's invocation, I've broken that out.

23:50 gfredericks: refactor/comment patches should just be jira tickets?

23:50 dnolen: gfredericks: yes please.

23:51 gfredericks: cool; I've had ideas in the past but didn't know how welcome they were. I'll be more proactive now.

23:51 dnolen: gfredericks: excellent!

23:51 gfredericks: look forward to the patch discussion :)

23:51 heading out

23:51 gfredericks: seeya

Logging service provided by n01se.net