Fork me on GitHub
#clojure
<
2019-06-29
>
theeternalpulse02:06:39

How would I fully qualify a symbol from within a macro, but outside a qualified quote. For example if I use a sym and pass that into the macro, and get it's value to do some processing?

andy.fingerhut02:06:42

Not sure I understand the question. When you say you want the macro to get the value of a symbol that was passed as a parameter to the macro, and do some processing on that symbol, what kind of processing do you mean?

andy.fingerhut02:06:24

Or, do you have an example of what you want as the macro call, and the expanded version of the macro, that might help clarify?

andy.fingerhut02:06:38

The main reason that the syntax-quote (signified via a back-quote character) causes unqualified symbols within it to become fully namespace qualified, is to prevent accidental name collisions with symbols having the same name where the macro is called.

theeternalpulse02:06:42

this macro doen't work with the following input

(defmacro with-args
  "Bind "
  {:style/indent [1]} 
  [argv arg-bindings & body]
  (let [bind-list (->> (partition 2 arg-bindings)
                       (map-indexed (fn [i v]
                                      [(first v) i]))
                       flatten)
        bind-form (-> (apply hash-map bind-list)
                      (assoc :or (apply hash-map arg-bindings)))
        bind-arg (vec argv)]
    `(let [~bind-form ~bind-arg]
       [email protected])))

(let [args ["127.0.0.1"]]
  (with-args args
    [host "0.0.0.0"
     port "3030"]
    (tap> [host port])))

theeternalpulse02:06:11

it does with this

(with-args ["127.0.0.1"]
  [host "0.0.0.0"
   port "3030"]
  (tap> [host port]))

theeternalpulse02:06:24

it complains at the (vec argv) when it's a symbol, that it's not an Object[]

seancorfield02:06:19

Remember that macros operate on code before it is evaluated.

seancorfield02:06:06

so argv in your macro is args in that first case.

seancorfield02:06:29

You want (vec ...) evaluated at runtime, not compile time.

seancorfield02:06:07

so

`(let [~bind-form (vec ~argv)] 
  [email protected])

seancorfield02:06:38

(and remove the bind-arg local symbol)

seancorfield02:06:14

This is why the first rule of Macro Club is Don't Use Macros 🙂

theeternalpulse02:06:56

haha, I like taking a break from doing real projects to hit my head over fine macro details

introom03:06:51

i don’t get my mind on what spec is.

introom03:06:02

it seems to me it’s something wrapping the basic assert.

introom03:06:35

and the check is also happening at runtime. so if something wrong, it’s wrong.

seancorfield04:06:11

@i Spec is so many things. Yes, it does allow you to write assertions but that's not even scratching the surface. We use Spec very heavily in production code -- not assert style -- to describe data structures, so we can perform validation of API inputs and other things, and use the data from validation failures to provide custom, sensible responses to clients. We use Spec to auto-generate test data that we use in example-based tests. We use Spec to support generative testing of the properties behind our functions. We use Spec to provide development-time verification of function arguments under test. We use Spec to describe function behaviors so they can be generatively tested. We use Spec to describe data structures so that we can derive functionality from that -- such as CRUD functions, automatically generated via macros.

theeternalpulse03:06:20

have you used schema before?

theeternalpulse03:06:32

It's similar in that you can create contracts to your functions as to what data goes in and out, and ads other complex layers like pulling apart data based on the different parts of the specs. Also it has generative testing functionality that is as fined grained as the specs themselves.

Cora (she/her)03:06:01

is there a reverse comp, where the functions are applied left to right?

Cora (she/her)03:06:08

I know you can use threading for this

Cora (she/her)03:06:47

I like comp better but not so sure of the right to left evaluation

hiredman03:06:24

(comp (partial apply comp) reverse list)

Cora (she/her)03:06:51

hrm, I mean, thanks for that, but I meant to ask if there was something in core that does it already

Cora (she/her)03:06:48

guessing that's not the case now though

dpsutton03:06:42

I think comp “pushes” its functions onto the args. So the rightmost hits it then the next, etc

Cora (she/her)03:06:43

that's probably a good way to think about it

andy.fingerhut03:06:49

Nothing in core works the way comp does, except with reverse order of args

Cora (she/her)03:06:07

alrighty, thanks

seancorfield04:06:11

@i Spec is so many things. Yes, it does allow you to write assertions but that's not even scratching the surface. We use Spec very heavily in production code -- not assert style -- to describe data structures, so we can perform validation of API inputs and other things, and use the data from validation failures to provide custom, sensible responses to clients. We use Spec to auto-generate test data that we use in example-based tests. We use Spec to support generative testing of the properties behind our functions. We use Spec to provide development-time verification of function arguments under test. We use Spec to describe function behaviors so they can be generatively tested. We use Spec to describe data structures so that we can derive functionality from that -- such as CRUD functions, automatically generated via macros.

didibus04:06:30

Ya, you just got to learn to love comp, even though the ordering is opposite of intuition, depending what intuition you have, since in math right to left makes sense for composition: f * g is first g, then f. And you can think of it as just f(g()). So comp is the same: (comp f g) is like (f (g)) or f * g. I also don't find that ordering intuitive, but I'm pretty sure this is why comp works the other way. To make it extra confusing, but also convenient, transducers composed with comp apply left to right: (comp (map inc) (filter even?)) will first increment, and then filter. It makes it more confusing, because now you have to ask yourself if comp is used with transducers or not. But, when you do use transducers with it, which is what I most often use it for, it is in the more intuitive ordering.

Cora (she/her)05:06:00

that's odd about the left to right with transducers

Cora (she/her)05:06:25

I was using it as part of a threading macro as (map (comp #(update-in % [0] parse-count) vec rest))

Cora (she/her)05:06:38

so, right-to-left

Cora (she/her)05:06:07

now I'm wondering if there are places I can use transducers left to right with comp that'll improve my code

seancorfield05:06:58

The issue with transducers is that things like (map inc) and (filter even?) are transforms -- so they compose in the opposite direction to "regular" functions.

seancorfield05:06:42

In other words, you're not composing functions, you're composing transforms -- and they inherently work outside in, rather than inside out.

seancorfield05:06:51

Transducers are really interesting higher-order functions and figuring out how to write them -- with three arities (0, 1, and 2 arguments) -- teaches you a lot about function composition.

Cora (she/her)06:06:37

do you know of any good resource on understanding transducers?

dmaiocchi12:06:18

in this book transducer are covered. and It might be that Rich was inspired by this, since he mention also in his list of books.. But this is just speculation 🌕

Cora (she/her)14:06:20

hmm I have a copy of that somewhere. thanks!

seancorfield06:06:40

There's a follow-up Rich Hickey talk that deep-dives into stuff if you need it.

Cora (she/her)06:06:44

I think I watched part of that video

Cora (she/her)06:06:52

but I was too new to clojure at the time

seancorfield06:06:12

Anywhere you might use ->> and a multi-stage pipeline, you can use transducers.

Cora (she/her)06:06:12

now I know enough to be dangerous, so it's time to get lost in minutiae

Cora (she/her)06:06:26

I use that a lot

Cora (she/her)06:06:37

so yeah, maybe I should figure this stuff out 🙂

Ahmed Hassan06:06:01

@seancorfield what is multi-stage pipeline?

seancorfield06:06:33

(->> data
     (map foo)
     (filter bar)
     (map quux))

👆 4
seancorfield06:06:00

(into []
      (comp (map foo)
            (filter bar)
            (map quux))
      data)

👆 4
Cora (she/her)06:06:34

I found this part of the FAQ interesting, about transducers https://clojure.org/guides/faq#transducers_vs_seqs

Cora (she/her)06:06:02

the whole single-pass transformations thing

Cora (she/her)06:06:28

so I guess I can express something as a pipeline but iterate over the sequence only once

Cora (she/her)06:06:40

that seems like a pretty significant win

Cora (she/her)06:06:02

if I'm understanding that right

seancorfield06:06:06

Yes, where we used to have clojure.java.jdbc/query and then post-processing, we're switching to next.jdbc/plan and a reduce or transduce operation.

Cora (she/her)06:06:23

I think I need to read the source of comp and some transducers to really understand this

seancorfield06:06:11

I dunno. I didn't need to read the source to make sense of this. If anything, I think the source is confusing.

seancorfield06:06:49

The abstractions are a lot more important than the implementations.

Cora (she/her)06:06:42

I like to get an understanding of how it actually works, even if fuzzily, to build intuition. it seems to work for me

seancorfield06:06:23

Yes, that's the follow-up talk I alluded to above.

misha06:06:21

I wish comp for regular functions worked in the same direction comp for transducers does

Cora (she/her)06:06:47

that's what started this whole thing for me today, wanting that 🙂

seancorfield06:06:43

Ah, and once you understand everything, comp behaves exactly as it should 🙂

misha06:06:42

but, but, but, you just told that implementation details are not important! kappa

seancorfield06:06:09

That's not quite what I said...

Cora (she/her)06:06:49

I see that it just nests them

misha06:06:05

-> is always be the right comp in my heart

misha06:06:19

if you search for that on github - you'll find out it is not quite new idea ;)

Cora (she/her)06:06:24

I learned of list* from this, so that's worth it

seancorfield06:06:56

Several "special forms" foo are actually macros that are implemented in terms of foo* compiler forms.

vlaaad06:06:42

I prefer -> to comp where possible, but comp still has valid use cases, where order of arguments to comp corresponds to order I'm which computation happens (transducers for example`)

misha06:06:32

how can order of args to -> not correspond...?

vlaaad07:06:42

In case of combining higher order functions like transducers or ring middleware

misha06:06:06

there is a thing with comp and/or -> lambdas e.g #(-> % f g h), where a an "anonymous" java class is generated on every call(? or something) instead of just reusing the same. I forgot in which case that is, since it did not affect me much. But one of the approaches results in cleaner runtime.

Cora (she/her)06:06:55

ok, I'm tired. time for sleep. cheers, everyone

dacopare10:06:45

Hi guys, I've written a Clojure library for the Event Store DB, and I'd really appreciate any suggestions you might have, and any stars you can spare! https://github.com/dcprevere/evst

dacopare10:06:12

I'll be making an up-to-date lib available on Clojars this evening.

tdantas15:06:20

hey, anyone using carmine 🙂 I’m trying to monitoring like this

(def listener
  (car/with-new-listener server1-conn
                         (fn [reply initial-state] (println reply initial-state))
                         {:initial-state true}
                         (car/monitor)))

tdantas15:06:36

but I’m only receiving the first reply “OK”

eggsyntax18:06:01

Anyone remember the existence of a lib or gist that lets you use datomic pull syntax on arbitrary clj data structures? I feel like I vaguely remember someone mentioning the existence of such a thing once, but no luck googling it. Otherwise I'll just write it (can post as gist if other folks would find it useful), but I'd just as soon grab it elsewhere if it already exists. Caveat: I'm looking for something that operates entirely independently of datomic, something that just uses the same or similar syntax for describing nested data structures.

eggsyntax18:06:02

Hmm. The timing's right in terms of when I think I heard about it, but I don't recall datascript letting you do pulls against arbitrary nested data structures (as opposed to collections of datoms). On the other hand, seems like with datascript you might be able to just create an ad hoc mini-DB... I'll go back & read some of the docs. Thanks!

eggsyntax18:06:06

Nah, as awesome as datascript is, and as lightweight as it is relative to datomic, I'm really looking for just a one-trick pony that lets you describe & retrieve a substructure of a typical, arbitrary, heavily nested clj/s data structure. Probably easier and funner to just write it 🙂

eggsyntax20:06:47

@U08BW7V1V not sure, but that's exactly what I was looking for! On the other hand, I've just happily whiled away the last couple of hours writing my own, so I may stick with that 😆 Although juxt's definitely has a few cool features that mine doesn't (shadow attributes, references). Thanks!

rgm20:06:06

Any time.

kuzmin_m20:06:53

Hi! I’m playing with new protocols feature extend-via-metadata. And satisfies? seems to be broken:

(defprotocol P
  :extend-via-metadata true
  (a [this])
  (b [this]))

(let [o (reify P
          (a [_] :a)
          (b [_] :b))]
  (satisfies? P o)) ;; => true

(let [o (with-meta []
          {`a (constantly :a)
           `b (constantly :b)})]
  (satisfies? P o)) ;; => false

alexmiller20:06:47

This is a known issue

Aron20:06:43

known by whom? 🙂

andy.fingerhut22:06:52

In my testing, binding *print-readably* to false and using println, print, pr-str, etc., rather than the default *print-readably* true, causes characters in a string value like newline and tab to be printed differently, but only affects the handful of characters, those in the value of clojure.core/char-escape-string

andy.fingerhut22:06:59

The doc string for *print-readably* says " When set to logical false, strings and characters will be printed with non-alphanumeric characters converted to the appropriate escape sequences."

andy.fingerhut22:06:23

Does "non-alphanumeric characters" there refer only to the handful in the value of char-escape-string, and no others?

andy.fingerhut22:06:10

If anyone happens to know of a built-in way to get more (or 'all') non-printable characters to be printed with escape sequences like \u1234, please let me know. Easy to implement myself I know.