Fork me on GitHub
#clojure
<
2016-12-13
>
ag00:12:11

any ideas of making something like this more elegant:

(defn fancy-fn [foo bar]
  (when foo (environ :env {:foo foo}))
  (when bar (environ :env {:bar bar}))
(do-something foo bar))

ghadi00:12:51

does environ have a side effect @ag ? You're throwing away the intermediate result of (when foo (environ :env {:foo foo}))

ghadi00:12:03

....also there is already a function in clojure called some-fn 😃

ag00:12:33

@ghadi ok, I have updated the snippet

ghadi00:12:29

it's hard to know what's elegant -- not sure what you're trying to do

ghadi00:12:16

if i'm rolling blind -- sounds like three side-effects -- I'd split into three functions... If I'm rolling blind.

ag00:12:16

no I mean side-effects aside, how can this pattern be improved? Maybe pattern matching or something like that?

jrheard02:12:20

maybe this is a crude approach, but if you have a lot of foos and bars, you could put them in a vector and iterate over that vector, performing your side effect on each one

jcromartie02:12:59

my 2 cents: it sounds like @ag is looking for a macro

lvh02:12:42

(defn ^:private twoflog
  "Finds the largest power-of-two k < n, i.e. such that k < n <= 2k."
  [n]
  (loop [k 1]
    (let [next (* 2 k)]
      (if (>= next n)
        k  (recur next)))))

(->> 1 (iterate (partial * 2)) (take-while (fn [k] (< k n))) last)
What’s the preferred implementation here? I kind of like how declarative the latter is, but....

lvh02:12:19

I guess it’d also be nice if there was shorter partial syntax (not currying, but still)

neupsh03:12:13

hi what is the best way to walk through two sequences comparing each positional elements?

lvh03:12:56

nux define compare? map takes multiple colls

lvh03:12:14

(map = xs ys) does what you might think

neupsh03:12:31

lvh cool let me try thanks

lvh03:12:51

clojure is great

leov06:12:58

hi all. Is there a library to (compare {:tempid 2 :val "hi"} {:tempid _ :val "hi"}) in tests and that compares by form and yields true in this case?

seancorfield06:12:14

I suspect core.match will get you some part of the way there...?

seancorfield06:12:28

boot.user=> (match [{:tempid 2 :val "hi"}] [{:tempid _ :val "hi"}] true :else false)
true

seancorfield07:12:13

Yup, or that. I always forget about that one.

02b88fc609:12:56

Any recommendation for a templating library for clojure? I want to generate an xml with dynamic data. Should I go with stringtemplate4 (used by antlr4) or something like selmer?

dominicm09:12:52

Selmer is pretty good & will work with with anything (not tied to any output format particularly)

02b88fc609:12:50

ok, will look into selmer. How does it compare with stringtemplate4?

02b88fc609:12:33

Both are similar right right? Except selmer is more clojure friendly?

dominicm09:12:06

Not familiar with stringtemplate4, but based on what I see from a quick look at the docs, that seems a fair assessment.

02b88fc609:12:54

ok, thanks @dominicm. I will try selmer first.

sirwobin10:12:47

anyone know where I can find a backup of yada documentation?

sirwobin10:12:57

http://yada.juxt.pro currently gives 502 error

sirwobin10:12:17

ah, the docs moved

dominicm10:12:06

Sorry about that! Moved them into the main site.

yenda11:12:55

On http://clojure.org the reference about the reader says that

Symbols beginning or ending with ':' are reserved by Clojure. A symbol can contain one or more non-repeating ':'s.
, is there symbols that actually begin with a colon and if so how does the reader differentiate them from a keyword ?

dominicm11:12:29

@yenda I think that what is being suggested is that a symbol (any combination of characters, more or less) starting with a : is actually a keyword.

dominicm11:12:42

It's a reserved "special case"

mpenet12:12:42

well, "should be" is more like it, there are always differences between what's what at read-time vs runtime, it's full of oddities

karol.adamiec13:12:34

hi, i have a namespace issue…

(ns server.core
  (require [datomic.api :as d])
  (:use ring.adapter.jetty)
  (:gen-class))

(defn -main
  "I don't do a whole lot ... yet."
  [& args]
  (println "Hello, World!")

  (defn handler [request]
          {:status 200
            :headers {"Content-Type" "text/html"}
            :body (d/q '[:find  [(pull ?id [* {:bracket/parts [{:part.spec/part [*]}]}]) ...]
                            :where [?id :bracket/name]
                          (d/db (d/connect uri))])})
  (run-jetty handler {:port 8000}))
after lein uberjar and running and curling i get back java.lang.RuntimeException: No such namespace: d, compiling:(NO_SOURCE_PATH:18:33)

chrisetheridge14:12:21

any reason why you cant do this?

(let [{:keys [some-number another]
       :or   {some-number another}} {:some-number 5
                                     :another       10}])

chrisetheridge14:12:50

(i get an unable to resolve symbol ‘another’ in this context)

chrisetheridge14:12:53

just interested as to why

igrishaev14:12:32

@biscuitpants because it's a wrong match in the or part. It should be smth like :or {:some-number 1 :another 42}

jonsmock14:12:10

@isaac_cambron Sorry this is so late, just saw your exchange earlier. Notice the (def f #'foo) vs (def f foo).

jonsmock14:12:58

I think Chas explains the trade-off in the video. I assume you're not doing anything high-performance (b/c how often are we really?) but if you are, I think there's a perf trade-off here

chrisetheridge14:12:04

oh really? thank you @igrishaev !

igrishaev14:12:49

@biscuitpants sorry w/o colons: :or {some-number 1 another 42}

lyndsysimon16:12:25

I'm having some issues with logging. I'm using clj-log, and my logs are all showing as coming from the user namespace. I've put together a minimal reproducible example here, which includes the output I'm seeing in the README: https://github.com/lyndsysimon/clj-broken-logging

lyndsysimon16:12:04

It seems like clojure.tools.logging is doing some magic somewhere to resolve the "actual" namespace, even when *ns* is user. clj-log isn't doing that.

darwin16:12:54

try to print *ns* directly in places where you call clojure.tools.logging/log

darwin16:12:52

ah, scratch my message, you were talking about clj-log, not a bug in clojure.tools.logging

darwin16:12:59

looks like clj-log is using runtime value of *ns*[1] that is wrong, they should use macro-expansion-time value of *ns* [1] https://github.com/yogthos/clj-log/blob/master/src/clj_log/core.clj#L33

lyndsysimon16:12:13

I dug through that code, but my Clojure ability isn't yet up to the task of solving this.

darwin16:12:25

you can easily test that they use runtime value, by binding *ns* to an arbitrary value before calling clj-log.core/log, it will happily print it as current namespace

bronsa16:12:46

@lyndsysimon the problem is that c.t.l uses a macro for log while clj-log uses a function

lyndsysimon16:12:52

Gotchya. OK, that should be enough information to start me down the right path.

darwin16:12:54

clojure.tools.logging/log will use your proper namespace, because namespace name was baked-in when the log macro was expanded

lyndsysimon16:12:12

Looks like it's time for me to learn to write a macro.

gfredericks16:12:21

this is my logging APIs need to be macros if they're going to capture the namespace

lyndsysimon16:12:31

That function looks small enough to cut my teeth on, too. Awesome.

lyndsysimon16:12:53

In all seriousness, it's past time that I dig into macros. I know what they do and when they should be used, I've just purposefully avoided learning the syntax to this point.

bronsa16:12:18

protip: there's no such thing as macro syntax

bronsa16:12:11

`~@ and friends are not "macro syntax", it's just reader syntax for expanding quoted data structures

lyndsysimon16:12:15

bronsa: Well, there is syntax that is only used with writing marcos. If you're referring to homoiconicity, I'm already in love with it 🙂

bronsa16:12:16

which happens to be handy when writing macros

bronsa16:12:25

no, that's the thing

bronsa16:12:32

it's not "only used with writing macros"

bronsa16:12:40

you can use it for whatever

lyndsysimon16:12:46

OK, cool. I'll correct my misconception.

bronsa16:12:02

ffs clojurebot

bronsa16:12:31

that was

`[1 2 ~@(when true [3 4])]
before clojurebot expanded it

chbm16:12:41

i’m sure there’s an awesome reason for conj behaviour re lists vs vectors. anyone can explain what it is ? 🙂

bronsa16:12:58

conj appends into the most efficient place for each collection

bronsa16:12:07

for linked lists it's the head

bronsa16:12:11

for vectors it's the tail

bronsa16:12:16

for sets it's undefined

chbm16:12:51

yeah that’s what i thought but for linked lists tail is at least as good as head

bronsa16:12:58

no that's not true

bronsa16:12:14

appending to the tail of a singly linked list is a linear operation

dpsutton16:12:16

depends on how you do the link list

dpsutton16:12:24

you can keep doubly linked, keep pointers to head and tail, etc

dpsutton16:12:31

but seqs in clojure are singly linked lists

chbm16:12:33

“suficiently good linked list” 🙂

dpsutton16:12:34

with no reference to tail

chbm16:12:46

but yeah head is better for immutable

lyndsysimon16:12:03

I assume Clojure uses forward-linked lists? If so, adding to the head will require modifying one object (the one you're adding). Adding to the tail requires modifying two (the one you're adding and the one that was last in the list).

lyndsysimon16:12:18

"modifying" is a simplification, obviously 🙂

tbaldridge16:12:26

Clojure uses single linked lists

darwin16:12:33

(not tested)

chbm16:12:47

seems like a weak reason for an api behaviour quirk

tbaldridge16:12:57

@lyndsysimon so you can only add to the head of lists

chbm16:12:01

really hard to think in car/cdr this way

bronsa16:12:05

it's not a behavioru quirk tho

dpsutton16:12:08

@lyndsysimon you need a reference to the tail to add to it

tbaldridge16:12:12

Vectors allow you to append at the end

dpsutton16:12:12

and to get that you have to traverse your list

bronsa16:12:21

conj is not defined to work on sequences, but as a polymorphic operation on collections

bronsa16:12:42

meaning it will insert the element in a way that makes sense for the collection, in the most efficient place for that collection

bronsa16:12:12

conj is not cons

chbm16:12:15

it’s a big gotcha, totally opposite behaviour on similar types

bronsa16:12:24

it just so happens that conj behaves like cons for lists

chbm16:12:58

leads to “i don’t know what this code cause it depends"

bronsa16:12:03

it's not a quirk or a gotcha, it's a fundamental language design choice

chbm16:12:43

you’re looking at a function and unless you know its call chain you don’t know the outcome. that’s poor design

bronsa16:12:46

the intended consequence is that you have to reason about what data structure is the best to use in your code

chbm16:12:33

(defn [x xs] (conj xs x))

chbm16:12:36

what does that do ?

tbaldridge16:12:43

it adds something to a collection

bronsa16:12:53

appends x to xs in the most meaningful place for xs as a collection

bronsa16:12:59

it doesn't promise anything about order

bronsa16:12:06

so it's meaningless to expect knowledge about that

tbaldridge16:12:07

notice that conj also works with sets (adds the item to the set) and with hashmaps if val = [k v] in which case it adds a new key/value

lyndsysimon16:12:15

I'm coming from Python, mostly. One of the things I look for in evaluating potential Python devs is how they choose between tuples, lists, and sets. Devs who understand Python's type system very well tend to use lists only if they are forced to. This seems similar.

dpsutton16:12:23

(defn [x] (+ 1 x)) @chbm what does this do?

chbm16:12:41

throws hard if you pass it a string ? 🙂

dpsutton16:12:49

haha exactly what i was gonna say

chbm16:12:56

but yeah I get the point

dpsutton16:12:58

you always have to reason about the underlying type

dpsutton16:12:22

in clojurescript, does that fall back to the overloaded plus and do appends and string coercing?

mpenet16:12:27

same as (defn [x y] (+ y x))

mpenet16:12:37

lots of possible return types

mpenet16:12:59

if we had operator overloading could be even worse. nothing new under the sun

chbm16:12:12

so, whats the cdr to cons ?

chbm16:12:38

(pretend that made sense)

dpsutton16:12:47

my favorite type of question

dpsutton16:12:56

conj to cons as rest is to cdr?

bronsa16:12:36

that's a meaningless question, conj is not a parallel to cons. they're different operations. in clojure both conj and cons exist

bronsa16:12:40

they just work on different abstraction levels. conj works on collections, cons on sequences

chbm16:12:25

list append then

chbm16:12:40

(flatten (list '(1 2 3) 4))
this

bronsa16:12:31

you can use concat to "append" to the tail of a collection

bronsa16:12:46

(concat '(1 2 3) '(4))

bronsa16:12:15

but generally if you need to append to the tail, it's a sign you don't want to use a singly linked list

dpsutton16:12:12

to me it looks like conj:car :: rest:cdr

bronsa16:12:55

no that's nonsense

dpsutton16:12:05

well, its an analogy

bronsa16:12:11

car returns the first element of a list

bronsa16:12:14

cdr returns the rest of a list

bronsa16:12:18

conj appends

dpsutton16:12:19

i don't think its nonsense

dpsutton16:12:30

ah you're right.

dpsutton16:12:37

i meant to car

dpsutton16:12:53

just analogues for chbm above

lyndsysimon17:12:57

@darwin - I've got my logging problem half fixed 🙂

Alex Miller (Clojure team)17:12:39

and going meta, if you see a “frequently asked question”, check the faq first. if it’s not there, file an issue or send a PR to https://github.com/clojure/clojure-site - I would love for these kinds of questions to be easily redirectable to a central edited answer

chbm17:12:51

i was actually on clojuredocs, that needs to be linked in a comment 🙂

Pablo Fernandez18:12:57

Anybody having any problems doing Clojure on Mac OS Sierra?

robert-stuttaford18:12:56

… well, it won’t write my code for me, yet. i still have to do that bit myself 🙂

jrheard18:12:27

@pupeno are you seeing problems and want to see if anyone else sees the same problems, or are you just double-checking before upgrading?

Pablo Fernandez18:12:55

@jrheard double checking before upgrading.

jrheard18:12:09

(i haven’t upgraded yet, glgl 😄 )

Pablo Fernandez18:12:23

I’m getting older… I’m letting other people suffer the first-mover pains 😉

bill18:12:36

@bronsa conj works fine on sequences:

(type (conj (range) :x))
clojure.lang.Cons

bill18:12:29

boot.user=> (take 2 (conj (range) :x))
(:x 0)

bronsa18:12:57

@bill range is both a sequence and a collection

bill18:12:37

all ISeq are both ISeq and IPersistentCollection right?

bill18:12:13

i.e. there is no sequence that is not also a collection

bronsa18:12:29

yes, that's correct

bronsa18:12:29

should have said, sequences are also collections

02b88fc618:12:54

Any idea why the clojure jar does not have history enabled under bash (Ubuntu)? Same jar works fine in Windows.

02b88fc618:12:47

The up arrow does not bring previously typed values.

hiredman18:12:55

the repl doesn't have any built in history or line editing

hiredman18:12:13

if you are seeing it on windows then that functionality is coming from somewhere else

02b88fc618:12:36

means windows cmd does that automatically?

hiredman18:12:50

dunno, but it isn't coming from clojure

hiredman18:12:59

rlwrap will add it

02b88fc618:12:15

yes, I am using rlwarp. But was thinking why it's working in Windows.

hiredman18:12:25

ok, are you using rlwrap on ubuntu?

02b88fc618:12:11

yes to get the history. lein repl also works fine.

uwo19:12:40

is there a way to get pprint to print tempids as tagged literals instead of like {:part :db.part/user :idx -123}?

uwo19:12:17

(datomic tempids)

dominicm19:12:41

I think pprint is protocol based

dominicm19:12:10

So you could implement something custom for that type

uwo19:12:39

@dominicm groovy, thanks!

neupsh20:12:11

Hi, can we pass :or while destructuring a vector?

neupsh20:12:35

(let [[a :or 3] []](println a)) does not work

neupsh20:12:03

I get Exception Unsupported binding form: 3

lyndsysimon20:12:59

@darwin 3.5 hours later, I can write macros.

jr20:12:14

user=> (let [{a 1 :or {a 3}} [1]] a)
3

jr20:12:59

user=> (let [{a 0 b 1 :or {a 3 b 6}} [1]] [a b])
[1 6]

neupsh20:12:19

@jr is that like converting vector to a map for destructuring?

jr20:12:35

the destructure mapping is symbol to index instead of symbol to keyword (when destructuring maps)

darwin20:12:24

@lyndsysimon congrats, that was fast 🙂 looks good to me, but make-message bakes in time at macro-expansion time, that is not what you want

neupsh20:12:45

@jr i see thanks a lot

lyndsysimon20:12:08

Hmm... I see that that happens, but I'm not seeing the negative impact. Why don't I want that?

darwin20:12:15

well, I would expect log data to contain :time representing runtime time the log was logged, not time when the code was compiled

darwin20:12:58

you are calling make-message in a macro during compile-time

lyndsysimon20:12:39

Gotchya. I should handle it in log like I do it in logf

lyndsysimon20:12:04

Unquote the function, not the form where it's called.

darwin20:12:39

btw. make-message or log-message in logf are not necessary, it is the default behaviour of syntax-quote to provide fully qualified namespace to symbols which are not fully qualified

lyndsysimon20:12:45

Hmm. OK. I was getting an error that the symbols were undefined in the current namespace, but that was much earlier and who knows how much I've changed and learned since then.

lyndsysimon20:12:49

java.lang.IllegalStateException: var: #'clj-log.core/make-message is not public

darwin20:12:30

aha, didn’t think that this would be a problem

lyndsysimon20:12:37

Good deal 🙂

darwin20:12:02

btw. there is still some room for optimization

darwin20:12:20

right now you are doing (merge message-info# exception-info#) at runtime

darwin20:12:34

I think you should think to do as much work as possible at compile time

lyndsysimon20:12:50

I'm happy to learn.

darwin20:12:57

I would call make-message and ex-log at compile time and merge them at compile time and then simply emit resulting static map, with :time to be emitted as having value (new Date)

darwin20:12:22

look at your current result from log macro using macroexpand-1

darwin20:12:42

and try to do as much work as possible at compile-time, but be careful not to emit huge amounts of code, it is always a tradeoff, either you want to optimize for speed (e.g. logging in a tight loop) or code size (e.g. logging all over the place and you don’t want to balloon your code size much)

leov20:12:14

coming from Ruby, I actually have a long-standing question in my 2 years of learning clojure. how does one debug clojure code? is there something compared to binding.pry repl of ruby? I use vim, and maybe that's why I have this problem. I heard that Cursive has a full-blown breakpoints/local state inspection/modification and other IDE debugging features I remember from C# IDE.

zane20:12:42

Honestly I've never needed anything other than clojure.tools.trace.

hiredman21:12:04

I use println, and logs, same as I use with any other programming language 🙂, the main difference with clojure there is the repl is more first class, with other languages either they don't have a repl, or it is second class to running code from a file

leov21:12:18

ruby has first-class repl

leov21:12:23

*rails has.

dpsutton21:12:31

i step through line at a time in CIDER

leov21:12:25

so there is nothing like cd-cause to jump to current exception to investigate program state?

hiredman21:12:31

leov: by other i meant "some other"

leov21:12:33

like 'break on exception' but inside repl

hiredman21:12:59

people have written tools like that, but they didn't see a lot of adoption

hiredman21:12:41

https://github.com/GeorgeJahad/debug-repl was maybe the first, but it may not work any more

hiredman21:12:23

it sounds like different tool chains have different kinds of mechanism like that, cider and cursive

hiredman21:12:04

but I've been happy with printlns and logging, and those work everywhere, so I cannot speak to them

hiredman21:12:56

https://github.com/gfredericks/debug-repl looks like an updated version of debug repl to work with nrepl, but nrepl is a lower level communications protocol, so you'll need a client and the client will have to support it too

seancorfield21:12:11

@leov does Rails let you have a live REPL into a running application so you can modify it on the fly?

hiredman21:12:43

clojure compiles to jvm bytecode and includes debugging information, so in theory you can use any java debugger with it

hiredman21:12:01

https://github.com/m0smith/cljdb people have built stuff using jdb (sort of like gdb for java)

leov21:12:26

inside Rails process - on breakpoints only. Inside live system - via database mutations (by spinning off another console process and doing changes to external services connected to your app. But more often it's excercising problematic code so that you can drop into exception context)

arrdem21:12:51

There’s also a debugger built in to CIDER of recent builds

seancorfield21:12:39

@leov If you have a REPL running in a Clojure app, it’s a full REPL: let’s you execute any code and redefine functions on the fly — so the debugging experience tends to be very different. You can enable and disable tracing, add and remove println / logging, fix bugs etc.

seancorfield21:12:13

I think the REPL is why we’ve not seen “traditional” debugging tools catch on with Clojure: we have something richer.

leov21:12:04

yes, but my usual and most powerful debugging procedure (worked 80% of the time, though, due to some recent ruby glitches) was just to run problematic code and then get the exception, and run cd-cause to drop into the context of where it happened. I guess it is almost like 'break on exception' in IDE

hiredman21:12:49

my observation on debuggers is people that want them really really want them, and people that don't, don't

leov21:12:11

in clojure with REPL I am doing more of a 'scientific method' (that is, guessing). I cannot put a breakpoint, slightly change state, and re-run a snippet. Instead, I'm changing the snippet in vim, so that the scaffolding paragraph/snippet is above or below the problematic code, rerun it, and the whole thing, surprisingly, comes slower for me.

hiredman21:12:54

I asked George to share the debugger kool-aid with me at the first conj, because I wanted to know why he cared so much about them, but I think he thought I may have been winding him up

trptcolin21:12:30

i think it would absolutely be useful to have a pry-like experience w/ clojure apps. the benefit that most people (including me) are missing now: events triggered by exercising the app out-of-band (e.g. web requests). a debugger solves some of that, but afaik doesn't get you as far as dropping into a full REPL on these out-of-band events. [i'd love such a tool, but not so much that i'm going to write it.]

arrdem21:12:15

the CIDER debugger will let you break on fns and get a debugger. I’ve successfully debugged asyc web requests that way.

arrdem21:12:26

Don’t know what other tools offer.

leov21:12:33

currently, because of REPL availability and debugging, I have these scaffolding 'test' snippets near half of my important functions

leov21:12:42

@trptcolin, yes, your description is more accurate. the problem is in out of band events, I guess

leov21:12:48

ok, I'll try to dig into tracing. Also I need to look into Cursive whether it has 'break on exception' thing

leov21:12:14

maybe it was just there all the time, with the full binding.pry power

leov21:12:24

(not vim, however)

hiredman21:12:56

well, that is a big difference from ruby, a runtime with real concurrency

leov21:12:08

GIL doesn't forbid real concurrency fwiw

val_waeselynck21:12:24

@leov I'm interested in discovering what Ruby/Rails has to offer in terms of interactive development. Do you have some good resources (videos, blog posts...) to share about this?

leov21:12:35

Pry-rescue with cd-cause command should outline the idea

leov21:12:18

I will try to look for a screencast tomorrow or maybe record one this week

hiredman21:12:03

my understanding is, at least as of summer this year, mri does not execute ruby code in parallel

leov21:12:23

it does not. however you can do IO In both os or green threads concurrently

zane21:12:37

Is clojure.algo.monads idiomatic for error handling?

Alex Miller (Clojure team)21:12:09

@leov there was a nice presentation at the Conj about Sayid, a tracing/debugging tool

leov21:12:54

thanks. will watch now

fellshard21:12:29

It was a pretty great demo!

zane22:12:13

@hiredman, what's more idiomatic?

zane22:12:33

The flow I'm trying to improve is essentially: transform -> validate -> handle errors if any -> transform some more -> repeat

hiredman22:12:51

usually, in cases where something like either or maybe seems appropriate, I tend to use a one off over pulling in algo.monads, but generally I stick to lists (monad wise) for which for is enough for me

hiredman22:12:08

I would say explicitly monadic code is not very common in clojure

zane22:12:45

Not sure I understand all of that.

zane22:12:55

What one-off would be appropriate here?

zane22:12:13

And how does for fit in?

hiredman22:12:50

for is a list monad, more or less

hiredman22:12:56

(technically sequences)

hiredman22:12:30

a one off might be returning a vector, the first element being a result, or the second an error

kingoftheknoll22:12:24

Can anyone recommend an article on better understanding why interning keywords "provide very fast equality tests -- http://clojure.org” and if the interning process is different from symbols.

tbaldridge22:12:30

IMO, monads are mostly a side-effect of dogmatically pure functional languages. You can use a monad or you can use a little bit of mutability. Often the latter is more idiomatic in Clojure.

hiredman22:12:52

using algo.monads is just fine, but if you are asking if that is idiomatic, and if idiomatic means "if you surveyed clojure code what would you see", then algo.monads is not

tbaldridge22:12:58

@kingoftheknoll keywords in Clojure are identical? if the names are the same. Not so with symbols.

tbaldridge22:12:49

identical? checks can be compiled down to a pointer comparison, where symbols must be compared by calling .equals (or .equiv) on the symbol.

hiredman22:12:13

core.logic has monads everywhere, but doesn't use algo.monads anywhere

kingoftheknoll22:12:24

As so fast equality checks keyword to keyword. I was thinking that meant if you had two maps with the same keywords that would be faster. But I know that maps do equality on value

hiredman22:12:34

clojurescript (atleast last I checked) doesn't always have identical? keywords, so if you are using clojurescript watch out for that

tbaldridge22:12:18

and hashmaps have special cases for keywords, if you look up something via a keyword it will use identical?

zane22:12:06

I've heard that before, @tbaldridge, and I generally agree. But I'm not sure how mutability would help me in this case.

kingoftheknoll22:12:09

So you’re saying the lookup is faster because key in the map can be found/resolved faster

dpsutton22:12:19

i had a similar situation, where it was going through a pipeline

zane22:12:30

Where "this case" is Either / Error.

dpsutton22:12:34

i made a macro that would check for errors and if none, attempt to perform its body

dpsutton22:12:35

so it was a macro that took a body, a "success" message to put, and a error message if there was an error

dpsutton22:12:02

so each step, if no errors, performed its action in a try/catch and put the error if that was caught

dpsutton22:12:14

then at the end it could summarize what had been done and what errors there were

hiredman22:12:14

I might have my transform function return a list of items instead of a single item, and just return an empty list on error

zane22:12:49

Right now the transformation and validation are separate.

dpsutton22:12:51

i actually destructured the data going through so it was an anaphoric macro with [{:keys [data success errors :as payload}] as the signature for everything

zane22:12:58

For some of the validators, anyway.

zane22:12:52

Yeah, it had occurred to me to do this with "middleware".

zane22:12:16

Where the validators call the next handler with their argument if they don't find any errors.

zane22:12:58

Essentially how Ring authorization is usually implemented.

cfleming22:12:44

@leov Cursive does indeed have break on exception, the most useful breakpoint IMO. I did a talk at Clojure/West about the debugger last year, which is mostly a demo but also talks about the limitations of debugging Clojure: https://www.youtube.com/watch?v=ql77RwhcCK0

tbaldridge22:12:31

@zane, I have to ask...thought of using spec?

tbaldridge22:12:45

it does a lot of of this error stuff

zane22:12:59

We use spec extensively.

zane22:12:15

But the validation I'm doing depends on runtime values (specifically a datomic schema).

tbaldridge22:12:53

I did a prototype of something like that, your predicates can refer to dynamic vars, or DB connections.

zane22:12:57

One of the validation steps is to conform the input to a generic spec (parsing), then a second one is to validate that parsed/conformed value against the datomic schema.

tbaldridge23:12:07

I'd be tempted to generate a spec from the datomic schema. Seems like it'd be a bit cleaner than writing a second validation framework

gfredericks23:12:19

@hiredman: test.check also has 3 or 4 adhoc monads

hiredman23:12:48

monads in monads to generate monads

gfredericks23:12:01

The monad monad

tbaldridge23:12:20

@gfredericks I've been interested in that, do you have a good paper on the design of test.check?

tbaldridge23:12:23

I'm wondering if monads are essential to the design of property based checking or if there's a better way. Since they do add a lot of complexity and mental overhead in a language like Clojure

zane23:12:38

I would but spec seems to actively resist that pattern.

zane23:12:47

Runtime generation that is.

tbaldridge23:12:27

There's eval (and yes I'm serious)

zane23:12:37

It also feels like there's maybe value in differentiating between syntax errors and non.

zane23:12:53

Eek. Haha

tbaldridge23:12:57

Seriously though, I'd love to hear an argument against eval in this context.

gfredericks23:12:42

@tbaldridge the quick answer is that test.check is monadic to the extent it was ported from haskell

gfredericks23:12:12

I haven't really thought about how you might design it from scratch

gfredericks23:12:30

back when I was paying more attention to cljs performance, I tried to think of a way to do something transduceresque to the shrink trees so they wouldn't create so many intermediate collections, but couldn't make it work

gfredericks23:12:49

now that I think about it, since it's a tree, I wonder if zippers would help...that might not make any sense

tbaldridge23:12:21

well yeah, that's been my thinking as well

tbaldridge23:12:44

I was able to remove monads from miniKanren, so I thought it might be possible here as well

gfredericks23:12:05

you got some benefit from doing that?

tbaldridge23:12:19

it's simpler code

gfredericks23:12:48

what did you replace them with?

tbaldridge23:12:03

transducers, so rule becomes keep, conjunctions become comp, etc.

gfredericks23:12:11

the difficulty I had with sprinkling transducers on the shrink tree was that it's two-dimensional

gfredericks23:12:42

and maintaining arbitrary navigation is valuable