Fork me on GitHub

Sorry if this is a silly question, but I'm really irritated by this. Why doesn't this overflow the stack? (reduce (fn [a b] (inc a)) 0 (partition 1 (range 10000000))) I have been noticing that several essential seq-functions are implemented as recursive functions returning lazy-seqs. This seemed weird to me, because I assumed they'd overflow the stack - but they don't. So I figure there must be something going on with how lazy-seqs are implemented, or what their semantics actually are, but I really don't get it.

Alex Miller (Clojure team)12:07:27

lazy-seq is not a recursive function, it is a macro


partition is recursive though

Alex Miller (Clojure team)12:07:39

lazy-seq is a macro expansion - it does not happen in the runtime call stack

Alex Miller (Clojure team)12:07:18

macro expansion happens at compile time, not at runtime


Okay I understand that. One step back though, artition features this line (cons p (partition n step pad (nthrest s step))) - why is this not recursive?

Alex Miller (Clojure team)12:07:05

because it's in the body of lazy-seq

Alex Miller (Clojure team)12:07:20

a simpler example to look at would be and or or


Is there a way to do stdio interactively with ProcessBuilder and and with a subprocess? Or what is the correct way of doing this?


I have something like this

Alex Miller (Clojure team)12:07:05

specifically ?


(let [pbuilder (ProcessBuilder. (into-array String ["..."]))
      process (.start pbuilder)]
  (with-open [reader ( (.getInputStream process))
              writer ( (.getOutputStream process))]
    (let [line1 (.readLine ^ reader)]
      (println line1)
      (.write ^ writer "test\n")
      (let [line2 (.readLine ^ reader)]
        (println line2)))))

Alex Miller (Clojure team)12:07:36

or for a lib with a lot more functionality,


@alexmiller ah thanks, the liberary seems to solve the buffering issues

Alex Miller (Clojure team)12:07:41

yeah, properly buffering and draining the process streams is tedious

Alex Miller (Clojure team)12:07:49

also, fyi the and can help with making buffered readers and writers


@finn.volkel Conch is part of clj-commons now, which is where maintenance and new releases happen /cc @alexmiller

clj 8

Hi guys! I'm running some tests though cider-test-run-* and I'm having a real hard time finding out if outputs I log in log/info are output anywhere during these tests


well then, looks like it outputs in the linked cider REPL. No clue how I missed that. Nothing like coming back from the weekend to solve your problems 🙂

cider 4

In C++ we can access maps/hashmaps with any kind of value (as long as there is a comparison function, or a hashing function), but in Clojure we can just interact with them with keywords, how can I achieve the same things if I can't use any kind of data? what is the Clojure-way of solving this?


You can use any object as a key


Keywords just happen to be very convenient


Please don't use mutable objects as keys - it makes bad things happen. But clojure won't stop you.


in fact there are built in functions in clojure.core that would be nearly useless if we didn't allow arbitrary keys

user=> (group-by count ["hello" "goodbye" "OK" "yes" "no" "stop" "start"])
{5 ["hello" "start"], 7 ["goodbye"], 2 ["OK" "no"], 3 ["yes"], 4 ["stop"]}


Oh, great, from what I have read it seemed that you weren't supposed to use nothing more than keywords as keys. So as long as I use immutable objects as keys there should be no problem, right?


right - strings, numbers, immutable data structures, symbols - all work great as keys

👍 4

keywords are common for implementing named fields, but you can mix in whatever makes sense for your domain


eg. I'd rather have "json key" as a key than attempt to turn that into a keyword


You can use maps containing maps containing maps containing sets of vectors as a key of a map, if you feel so inclined.


I can almost picture a use case for that


sometimes can be useful to make composite keys [primary-id secondary-id] with vectors, though rarely use anything but keywords or strings as keys


If you don't care if the map is sorted or not, then no comparison function is needed, the built-in clojure.core/hash function is used and works fine. If you want sorting, then the built-in clojure.core/compare function doesn't do anything useful for you to compare sets or maps to other things, and you may or may not want its default behavior for comparing sequential things to each other.


with group-by I end up using all sorts of keys


clojure.set/index builds maps of maps to sets


super useful


also, if you use memoize, you are implicitly using a map from List to Object


There are guide articles on writing custom comparator functions: and on a few corner cases of equality/hash for non-sorted sets you should avoid:


in the C++ case you probably have to implement a comparator / hash, with Clojure you rarely have to do this on your own (I haven't had to at all)