Fork me on GitHub
#clojure
<
2017-03-15
>
devn00:03:36

(.available input-stream) always returns 1 until it hits the RuntimeException

devn00:03:57

or rather, it always returns 1

hiredman00:03:28

yeah, I suspect the exception catching is the expected way to use it

hiredman00:03:52

java Readers throw EOFExceptions

devn00:03:07

It's just kind of a bummer to handle RuntimeException, no?

devn00:03:57

Any other suggestions are welcome

xiongtx00:03:59

@seancorfield Am I correct in understanding that with-db-connection in clojure.java.jdbc is useful only if you want to re-use the same connection for several different actions?

xiongtx00:03:18

B/c functions like insert! will automatically manage connections when given a DB spec

seancorfield01:03:31

@xiongtx Yes, that is correct. The recommended approach is to use a connection pool anyway, then you don’t need to worry about “reusing connections” — see http://clojure-doc.org/articles/ecosystem/java_jdbc/connection_pooling.html for examples

seancorfield01:03:29

Then you use the pooled connection (the map containing :datasource) as a db-spec in all calls.

ajchemist02:03:04

(ns interface.a)

(defprotocol X
  (x [this]))

(ns interface.b)

(defprotocol X
  (x [this]))

(ns test.defrecord)

(defrecord Example []
  interface.a/X
  (x [_] :a)
  interface.b/X
  (x [_] :b))

(interface.a/x (->Example)) ; => :a
(interface.b/x (->Example)) ; => :a (not :b)

ajchemist02:03:12

Is this expected?

ajchemist03:03:52

@tbaldridge now i see, thanks for the quick note

jmb05:03:15

I've recently picked up Quil since I thought it was interesting to see the digital art created with it. I'm curious though. Is Quil actually used in production or is it more of a toy library for programming pleasure purposes ?

jdeisenberg17:03:04

@jmb I am most interested in it as a vehicle for teaching functional programming with Clojure/Cljs as the vehicle. Quil (and Processing) make drawing/animation easy; this is attractive to students.

jmb18:03:10

Yeah I think Clojure is friendlier towards taking you to the FP realm compared to other FP languages. I asked because I wanted to specialize in a certain area of Clojure for blogging purposes. I don't mind blogging about Clojure in general, but it just felt too generalized. My choices of specialization in Clojure were either Quil, Reagent, or Datomic. I was probably gonna go with Reagent sprinkled with Datomic since it seems more valuable for web development purposes.

gklijs07:03:17

@jmb not an awnser to your question, but I also like quil because you can also use it in clojurescript, actually I used it in clojurescript first, but in some time I will try the same draw function in clojure.

olivermooney10:03:06

@jmb I’ve used Quil a fair bit but I’ve since moved to Karsten Schmidt’s http://thi.ng libraries: http://thi.ng

olivermooney10:03:11

Quil is good but it imoses sequencing issues on where you can do what, which kept tripping me up (I’d try to calculate something outside the drawing calls then found I couldn’t refer to the calculation how I’d like)

olivermooney10:03:58

The http://thi.ng libs don’t suffer from this. They’ve a much larger surface area, but there’s tons of great stuff in there if you’re into digital art generation

olivermooney10:03:40

Just noticed Karsten’s on Slack at @toxi

olivermooney11:03:03

I was at a http://thi.ng workshop on generative design last June, there’s a blog post about it (by Karsten) https://medium.com/@thi.ng/workshop-report-generative-design-with-clojure-7d6d8ea9a6e8#.208ff21e8

genmeblog11:03:42

you can try also my clojure2d (https://github.com/Clojure2D/clojure2d), where you can also can separate calculations from displaying stuff. Still poorly documented though but I prepared 20+ examples.

bfay14:03:16

I saw this pop up on github recently and it looks super-cool. Haven’t tried it out yet but I really like the motivation for the project and the example images you posted. Tangentially, do you have any recommendations for books/websites/other resources on digital art? I’ve been meaning to get back into it.

genmeblog14:03:31

Yesterday I posted on reddit answer to similar topic I copy it here

genmeblog15:03:23

And thanks for kind words about project. I'm moving from processing gradually to make all my stuff in Clojure. This library grows with me and my progress. I'll be doing live coding soon and such example also appear in repo.

bfay15:03:52

Thanks, I’ve seen some of the shiffman stuff (his enthusiasm is a thing to behold)! Definitely want to take a look at your generateme wordpress - I love it when people comment their process. Maybe I’ll try the blogging thing, seems like a good way to stay productive

genmeblog15:03:25

yeah, that's true

genmeblog15:03:05

I often get requests like "wow, can you elaborate how it's made?" and then I post a blog around the topic

kuzmin_m15:03:51

Hi! I wrote a new clojure/script routing library. It looks like ruby on rails routing but different. It have support for mountable apps and named routes. I will be glad to see the feedback. Please add star to repo If you like it. https://github.com/darkleaf/router

souenzzo16:03:44

I'm looking for function / data-driven routers (no macros)

kuzmin_m06:03:11

It use macro only for syntax sugar(defcontroller). DSL use plain functions.

lvh15:03:02

Specter seems to create new gensymd vars called “pathcache” in my namespaces

lvh15:03:06

can I make it… not do that?

nathanmarz15:03:48

@lvh that's a key part of how it achieves optimal performance

nathanmarz15:03:51

those are the inline caches

lvh15:03:05

can those be marked private, or live in a different namespace?

lvh15:03:22

(Otherwise I’m just going to use the * versions, which IIUC don’t do that?)

nathanmarz15:03:30

if you use select*, transform* those aren't created, but you lose all the callsite optimizations

nathanmarz15:03:37

i'll look into that

lvh15:03:45

This is showing up in autocomplete tooling

lvh15:03:55

this project also incidentally does a lot of namespace enumeration

lvh15:03:27

if it was like com.rpl.specter.pathcaches.my.full.namespace/pathcache12345 I wouldn’t care

lvh15:03:45

(also if it was marked private it’d be … marginally better, this code would still care but presumably my editor wouldn't)

qqq15:03:13

I want more info than (read-string (slurp fname)) I want the precise column/row of every symbol. The meta information si only provided on lists/vectors, but not every symbol (like string + number).

bronsa15:03:31

tools.reader has an indexing reader that adds meta information to symbols/lists

bronsa15:03:39

but non IObj items won't have it

nathanmarz15:03:44

@lvh easy fix, now in master

bronsa15:03:46

you can't use a reader if you need that

bronsa15:03:56

you need to use a parser

qqq15:03:19

@bronsa: tools.analyzer.jvm <-- is there a simple way to use this?

qqq15:03:33

I'm seeing all these complicated examples, but I just want the tools.analyzer.jvm equiv of (read-string (slurp %))

bronsa15:03:53

tools.analyzer is not a reader

bronsa15:03:11

what do you need to do?

lvh15:03:46

@nathanmarz Cool, thanks 🙂

qqq15:03:23

I'm writing a STLC type checker for a subset of clojure. I need to take a *.clj file, display it in SVG, and then annotate it with type info. For the "display in SVG part" -- I really want it to match the original layout, not just some "prettyprint of sexp". @bronsa

bronsa15:03:06

that's impossible to do 100% accurately using a reader (which tools.analyzer uses)

bronsa15:03:50

a reader goes string -> data, some data (e.g. numbers/strings/keyword) doesn't have a slot for metadata so there's no way to annotate it with line/col/original whitespace/comments info

bronsa16:03:25

" #_(1) :asd"

qqq16:03:30

I thought tools.jvm.analyzer made everythin gwith {} maps

qqq16:03:40

where one of the field is the actual symbol, and the other fields ar emetal info like row/column

bronsa16:03:54

there's no way to read that string and know what was before the keyword

bronsa16:03:10

@qqq tools.analyzer analyzes a s-expression, not a string

qqq16:03:27

@bronsa: ah, that's what I got wrong; thanks for clarifying that.

bronsa16:03:28

if it needs to deal with strings, it first reads them using tools.reader

bronsa16:03:34

all the limitations of tools built on top of a reader thus cascade into tools.analyzer

qqq16:03:11

so (1) tools.analyzer can't help me since it does sexp -> lots of info; and at the sexp level, the strings / numbers don't ahve meta data (2) tools.reader can't help me since it does "string -> sexp", but again, at the sexp level, strings/numbers don't ahve meta data

bronsa16:03:18

i've thought about splitting tools.reader into a parser and a reader and having t.a use the parser before

bronsa16:03:45

but it's a significant amount of work (esp trying to keep parity with current performance) and I don't have time for it

qqq16:03:42

@bronsa: thanks for "verifying this can't be done with existing tools"; rather useful for time saved

bronsa16:03:55

doing what you're trying to do was never a goal of neither tools.reader or tools.analyzer

qqq16:03:12

@bronsa: I don't need support for reader macros. Are ther eother libraries I should look into (or just roll my own) ?

bronsa16:03:39

it sounds like all you need to do is parse a clojure source

bronsa16:03:43

use a parser

bronsa16:03:05

instaparse/parsley

bronsa16:03:25

there are a bunch of libraries for creating parses in clojure

bronsa16:03:43

dunno if any of them come with parsers defined for the clojure language but it should be easy

bronsa16:03:23

you mentioned you wanted to annotate type info tho?

bronsa16:03:31

doing that on a parse tree is not the best idea

qqq16:03:01

why not? suppose we have (+ x y) I want to display above it with + being float->float->float, x:float, y:float

bronsa16:03:33

parse trees don't know about the semantics of the language

bronsa16:03:48

they only know about the syntax

qqq16:03:07

yeah, but after I run the type checker, I want to display the types the checker inferred

qqq16:03:14

and for that, I'd like to just "overlay it over the source"

bronsa16:03:17

type checking/inference is run on the semantic level not on the syntactic level

qqq16:03:36

agreed, but I want to visualize the type info

bronsa16:03:59

if you're the parse tree just for overlaying info that you gather in other ways, then fine

bronsa16:03:19

but then you have the problem of having to match the parse tree with the type info

qqq16:03:06

suppose I had this problem: I want type info on every symobl in my source. How would I solve this problem? (I don't know anything better than what we hav ediscucssed so far).

bronsa16:03:42

that's not an easy problem to solve

qqq16:03:56

I agree.

qqq16:03:02

We're not even talking difficulty of type checking.

bronsa16:03:03

you also seem to be glossing over the fact that type checking in clojure is really hard

qqq16:03:30

I'm writing in a restricted subset of clojure where only STLC checkable programs are considered valid.

qqq16:03:40

I know that type checking clojure is impossible ala halting problem.

bradford16:03:01

Is there an example of using httpkit client to do streaming chunked transfer requests to a server? (I want to upload gzipped batches of files)

sova-soars-the-sora17:03:41

@bradford so not exactly a stream, but chunks...

sova-soars-the-sora17:03:13

let me snoop around, it sounds familiar

sova-soars-the-sora17:03:09

So, just to clarify a bit...

sova-soars-the-sora17:03:18

you have lots of files, you gzip them on client

sova-soars-the-sora17:03:35

you want to send them to the server in batches, have the srvr weave them together? @bradford

bradford17:03:04

Yes, thank you!

sova-soars-the-sora17:03:36

Well, http-kit has :multipart which may work for you out of the box.

sova-soars-the-sora17:03:50

but if the files are large, you may not care to read their contents into client memory before sending them

sova-soars-the-sora17:03:00

(not fully anyway)

bradford17:03:37

@sova That's correct. This is for a proxy network -- I have proxy clients that grab a few files, compress them, and send them back to the proxy server (which is running Pedestal). I'd like to simulate that client. Each server has about 200k open connections.

donyorm17:03:02

So I'm trying to solve 4clojure problem 85 (http://www.4clojure.com/problem/85) where you have to generate a powerset for the given set.I've solved it with a strategy that generates combinations of a certain size of the given set and joining the resulting sets together. It works for smaller inputs but times out for larger ones. I'm new to clojure and CS in general and wondering if there's a broad area I should tackle first as far as optimization goes. Here's my code:

donyorm17:03:17

(defn power-series2 [s]
  (if (= s #{})
    #{#{}}
    (set (let [get-series-ele (fn get-series-ele [cur-set size]
                                (set
                                 (if (= (count cur-set) (dec size))
                                   (map #(conj cur-set %) (apply disj s cur-set))
                                   (apply concat (map #(get-series-ele (conj cur-set %) size) (apply disj s cur-set))))))]
           (apply concat #{s #{}} (map #(get-series-ele #{} %) (range 1 (count s))))))))

sova-soars-the-sora17:03:39

@bradford ah client simulation. nice.

sova-soars-the-sora17:03:36

httpkit has http/response ... i use web sockets via sente for client->server. If you want to stick to http kit only....

sova-soars-the-sora17:03:51

@bradford and in the case of Sente, there is a #connected-uids {} or somesuch that keeps unique track of connected peers that have successfully had their<ring> :session variable set.

sova-soars-the-sora17:03:39

But in the case of httpkit, I'm not certain how I would ascertain that I had 200k simulated connections. There's no array that keeps track of all "connections" as far as i am familiar. perhaps someone else knows more.

bradford17:03:18

@sova Thanks for the advice! I'm not worried about simulating 200k connections, I just want to get the data right.

qqq17:03:07

Clojure should add this function -- stateful map --

(defn smap [s f lst]
  (letfn [(f1 [[s accum] x]
    (let [[sn y] (f s x)]
      [sn (conj accum y)]))]
    (reduce f1 [s []] lst)))

mars0i17:03:09

@jdeisenberg Processing is a very un-functional system. Quil tries to make it as functional-ish as possible, but I wonder whether it's a good approach for teaching functional programming. However, I have only tried Quil once, and probably didn't go about it the right way. fwiw there was an introductory book by Paul Hudak The Haskell School of Expression that focused on graphics. I don't know it well, and then you have to deal with all of the type stuff in Haskell.

qqq17:03:00

I don't feel HSoE was very graphics heavy.

qqq17:03:19

There was some stuff on FRPs, but that was about it.

mars0i17:03:45

@qqq OK well you probably know it better than I do. Sitting on my shelf but I never did much with it. It did have some focus on graphics, unlike most Haskell books I'd seen around that time.

mars0i17:03:06

i.e. "some"

qqq17:03:29

@mars0i : there was some stuff on reactive animations / frp systems -- but I think it was really "let's teach monads/functors" and dip it in a layer of graphics

jdeisenberg17:03:37

@mars01 Processing isn’t functional, but Quil, with its middleware that lets you send a “state” variable from (setup) into (draw) and other handlers makes things much more functional. See https://github.com/quil/quil/wiki/Functional-mode-(fun-mode)

qqq18:03:00

I've looked through https://clojure.org/guides/destructuring Is there a way to use ":as foo" with {:keys [row col]}

schmee18:03:17

yes, {:keys [row col] :as foo} 🙂

sova-soars-the-sora18:03:09

@bradford Ok, so you want to client-send chunks.

sova-soars-the-sora18:03:25

I think if you mess with the keepalive value, you may not need to, you can just invoke http/response over and over again

sova-soars-the-sora18:03:36

you're saying that you want to send one file in many fragments?

sova-soars-the-sora18:03:51

because then a stream is good, and people certainly do that.

sova-soars-the-sora18:03:00

Anyway, good luck sir.

bradford18:03:32

@sova thanks so much!

devn19:03:24

(defn load
  "When a transit writer writes to a target by calling transit/write
  more than once, multiple reads are required to get all of that data
  back out. Takes an input stream and reads in chunks until EOF is
  hit."
  [input-stream]
  (let [rdr (transit/reader input-stream :json)
        eof :_EOF_]
    (loop [res []]
      (let [chunk (try (transit/read rdr)
                       (catch RuntimeException e
                         (let [cls (when-let [cause (.getCause e)]
                                     (class cause))]
                           (if (= java.io.EOFException cls)
                             eof
                             (throw e)))))]
        (if (= chunk eof)
          (walk/keywordize-keys res)
          (recur (into res chunk)))))))
Could I get a spot check on this? Specifically the catch portion, pretty sure I'm Doing It Wrong™.

noisesmith19:03:45

devn just use two catch clauses

noisesmith19:03:25

devn in the first one do (catch java.io.EOFException _ eof) then the next (catch Exception e (throw e))

noisesmith19:03:33

or just skip the second catch really

noisesmith19:03:12

oh- wait, never mind - you care about the cause

noisesmith19:03:38

@devn the when-let is a bit silly, (class nil) just returns nil, so you can just do (let [cls (class (.getCause e))] …) or even (if (= (class (.getCause e)) java.io.EOFException) …)

noisesmith19:03:46

@devn also the source of my initial confusion is that when I read on an empty transit stream, I get EOFException directly, not as a nested cause

noisesmith19:03:08

maybe this has to do with the type of the stream you are using?

noisesmith19:03:55

kingfisher.core=> (cognitect.transit/reader (java.io.ByteArrayInputStream. (byte-array 0)) :json)
#object[cognitect.transit.Reader 0x38cc9e60 "cognitect.transit.Reader@38cc9e60"]
kingfisher.core=> (cognitect.transit/read *1)

EOFException   com.cognitect.transit.impl.JsonParser.parse (JsonParser.java:44)

noisesmith19:03:02

@devn also, any particular reason to keywordize? I find it odd since transit supports keywords directly, unless you disagree with the producer of the data what the data should look like I guess

noisesmith19:03:10

@hiredman oh - thanks, that was misleading

devn19:03:42

@noisesmith the stuff that's being read comes from a ruby application

devn19:03:53

which writes strings IIRC

noisesmith19:03:17

OK - I mean it’s transit so they could write keywords if they wanted to I assume

devn19:03:19

perhaps I should verify that's the case, though!

devn19:03:47

@noisesmith I'm using a gzipinputstream

noisesmith19:03:13

yeah- hiredman pointed out my repl printed EOFException but it was actually a RuntimeException though

genmeblog19:03:18

@qqq your stateful map is not lazy, am I right?

noisesmith19:03:33

tsulej lazy version

(defn smap
  ([f coll] (smap (first coll) f (rest coll)))
  ([s f coll]
   (if (empty? coll)
     nil
     (lazy-seq
      (let [[s' el] (f s (first coll))]
        (cons el (smap s' f (rest coll))))))))

noisesmith19:03:46

> (smap (fn [acc el] [(+ acc el) (* acc el)]) (range 10))
(0 2 9 24 50 90 147 224 324)

qqq19:03:14

@noisesmith : but that consumes more stack space than normal map right?

qqq19:03:26

@noisesmith : i used the reduce there in hopes it'd be constant stack space

qqq19:03:42

(cons el (smap s' f (rest coll)) <-- looks like stack depth = O ( list length )

noisesmith19:03:05

qqq lazy things don’t consume extra stack, unless you stack lazy operations without realizing them

noisesmith19:03:21

which this doesn’t do (as long as f doesn’t do it)

genmeblog19:03:46

ok, I have similar solution here in my short article about signal processing (with lazy-seq)

noisesmith19:03:23

qqq because lazy-seq turns its arg into a thunk - the self calls are each “lifted” up out and not nested in a deeper stack frame

genmeblog19:03:30

but was criticized by someone on reddit

qqq19:03:55

@noisesmith : I must be missing something. Can you explain to me how lazy-seq causes

(cons el (smap s' f (rest coll))
to not create a bunch of (cons el waiting-for-return-value) stack frames ?

noisesmith19:03:12

qqq because smap returns a lazy-seq

noisesmith19:03:25

so it returns (cons el -lazy-)

qqq19:03:26

alright, so when I do a "doall" on the smap

qqq19:03:34

what happens?

noisesmith19:03:39

qqq then doall evaluates each thunk individually

noisesmith19:03:54

the thunks are each a closure that knows how to generate the next item

noisesmith19:03:04

they are not deeper in the stack compared to the previous item

qqq19:03:18

how do you not have a bunch of stack frames of the form (cons 1 ...) (cons 2 ...) (cons 3 ...) (cons 4 ...)

noisesmith19:03:35

qqq because lazy-seq doesn’t return a list

noisesmith19:03:02

it turns its arg into a function, that you call to get the next item

noisesmith19:03:13

a doseq can just take each next item, without going deeper on the stack

noisesmith19:03:36

qqq how large a collection do I need to pass in to ensure a stack overflow happens? I’m glad to show a counterexample with my function

noisesmith19:03:53

=> (last (smap (fn [acc el] [(+' acc el) (*' acc el)]) (range 1000000)))
499998000002499999

noisesmith19:03:58

I’ll go larger if you like

qqq19:03:00

@noisesmith: your explainatino makes sense now

qqq19:03:30

My argument was: but it has to create the entire list, thus there are all these (cons 1 ...) (cons 2 ...) (cons 3 ...) calls lying around your arugment is: no, the list is processed one item at a time you want 1 item okay, it 'forces' the lazyseq, gets (cons BLAH (lazy-seq2)) it returns BLAH back to you you want item 2 it 'forces' lazyseq2 gets (cos FOO (lazyseq3)) it returns FOO back to you you want item 3 .... so at any point, (1) what is "realized" has already been returned to you (2) what "reamisn" is a lazy-seq

qqq19:03:40

@noisesmith : is the above approximately correct?

noisesmith19:03:52

yes, that sounds about right

qqq20:03:11

this is like haskell's "weak head normal form"

qqq20:03:20

I just didn't realize it also avoided stack frames; this is clever as heck

genmeblog20:03:29

used the concept of lazy-seq in process-signal

genmeblog20:03:51

and got such comment on reddit: This reads like reinventing the wheel. Swapping sample and state in the filter functions and changing state's shape to match the output reveals these are actually reducing functions. process-signal simplifies to reductions + map, no need to build lazy sequences by hand.

genmeblog20:03:18

I agree that process-one-sample can be build in terms of reduce

genmeblog20:03:38

but process-signal?

noisesmith20:03:41

tsulej the advantage to your approach is that you can generate individual elements of a very long series without holding the whole thing in memory

noisesmith20:03:13

the advantage of reduce would be avoiding the laziness abstraction - I don’t think that is neccessarily a big win here

genmeblog20:03:11

signal usually is a stream, that's why lazy-seq is best here (I don't usually want to process whole stream at once)

noisesmith20:03:30

on the other hand, reductions could be an elegant approach here (it’s also a decent way to get the most common usages of smap)

noisesmith20:03:01

but reductions shares the same quality of being lazy that your code has - it’s just a specific abstraction

noisesmith20:03:19

I bet that code would be pretty tight if you used reductions

genmeblog20:03:38

cool, will investigate it

qqq20:03:32

@noisesmith: is there a more generiic than lazy-seq? for things like trees, or maybe something that had 3 children nodes ?

noisesmith20:03:58

not that I know of, and not in clojure.core

noisesmith20:03:33

closest would be a lazy-seq of lazy-seqs I guess (each element having N lazy-seqs inside it)

qqq20:03:41

I dont' ezpect lazyseq to turn arbitrary recursive defs into constant stack space via laziness

qqq20:03:02

but it seems like there's some class, more generaly than just laszy list, but less general than arbitrary recursion, that can be forced into constant stack space by 'lazy expanding stuff'

noisesmith20:03:25

qqq well they aren’t defs, but they will - each item in the spine contains N thunks you can follow if you wish

noisesmith20:03:51

as long as N is reasonable, the space usage can be reasonable (if you consume it smartly)

noisesmith20:03:37

or, you could have a lazy-seq of lazy-seqs as each item on the lazy-spine, if you want to go that far, but I think the resulting code would likely start to get messy

qqq20:03:29

eh, just wrap every sexp in a lazyseq 🙂

noisesmith20:03:52

that works great until you want a number or a string or something

qqq22:03:27

are there official regexps for 'symbol 'keyword 'number .... in clojure ?

qqq22:03:32

(for lexing clojure code)

bja22:03:18

@qqq there are some regexeps in the clojure.tools.reader project

bja22:03:38

it seems that way. I only knew about the numbers because I needed that once

qqq22:03:08

interesting; I was wondering why you knew that regexps existed in the clojure tools reader impl files

qqq22:03:02

on a related note, is there a clojure lexer that I can hijack?

qqq22:03:08

read-string is "string -> sexp"

qqq22:03:16

I'd prefer to get "string -> list of tokens" instead

bja22:03:52

I just checked, and LispReader.java has what you want

bja22:03:31

I don't know offhand of any clojure lexer that has a public interface, but you can probably hijack LispReader.java with some effort

qqq22:03:22

I'm actually writing a parser of sorts in cljs (posted in wrong channel), so will likely hack on top of https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/reader.cljs

qqq22:03:29

but the regexps you've shown me are going to be useful; thanks!

qqq22:03:16

any idea why https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/reader.cljs#L421-L439 <-- is named macros? it looks like the primary switch statement; I have noidea what it hsas to do with amcros

bja22:03:53

that's a dispatch table for reader-macros

bja22:03:17

the way the reader works, there are builtin reader macros (defined in that cond) and then an alternate dispatch table (triggered by \#) for what we call tagged literals

tbaldridge23:03:19

@qqq yeah, you want to write your parser a lot like LispReader. Clojure's reader is a lot like a state machine, esp since cljc was added, now there's just too much to track to leave it to regexes.

ag23:03:08

anyone here use spyscope with boot? can you guys tell me how to properly set it please

ag23:03:25

having problems with data-readers