Fork me on GitHub
#beginners
<
2020-02-19
>
seancorfield00:02:04

You can't in Spec 1. In Spec 2, you can do that for unqualified keys but not qualified keys.

seancorfield00:02:33

(and you are using unqualified keys -- :req-un -- so you'll be happy with Spec 2 in that regard.

Isaac Ballone01:02:47

(-> {:a 20 :30}
    :a)
=> 20

(-> {:a 20 :b 30}
    (:a))
=> 20
I thought this was a little weird... Is there a preference? Why do they produce the same result?

noisesmith01:02:36

-> isn't a normal function, it's a macro that automatically adds parens if they are absent

noisesmith01:02:57

I prefer to always use parens for consistency, but part of the point of -> is to reduce character count, so

noisesmith01:02:31

user=> (source ->)
(defmacro ->
  "Threads the expr through the forms. Inserts x as the
  second item in the first form, making a list of it if it is not a
  list already. If there are more forms, inserts the first form as the
  second item in second form, etc."
  {:added "1.0"}
  [x & forms]
  (loop [x x, forms forms]
    (if forms
      (let [form (first forms)
            threaded (if (seq? form)
                       (with-meta `(~(first form) ~x [email protected](next form)) (meta form))
                       (list form x))]
        (recur threaded (next forms)))
      x)))
nil

noisesmith01:02:46

the magic happens in the (if (seq? form) ... (list form x))

noisesmith01:02:00

so in the else, when it isn't in parens, it puts it in parens

Isaac Ballone01:02:29

Oh neat! So even if I don't put it in parens, it'll do it for me. I was thinking about leaving it in anyway for consistency, like you said. It just made me curious because I was surprised it was allowed

noisesmith01:02:00

it's pretty common to see both, but it's definitely good style to pick one and stick to it, per project at least

Isaac Ballone01:02:42

Okay, thanks for your help!

MC01:02:10

Not sure if your above was just an example of using one of the threading macros, but in said example, you really dont need it:

({:a 20 :30} :a)
=> 20

MC01:02:18

gives you the same result

Isaac Ballone01:02:41

It was just an example πŸ™‚

hindol03:02:07

Parens are added only for single arg fns.

seancorfield04:02:13

@hindol.adhya Not quite: the parens are added wherever there aren't parens. Consider (-> 42 cons) -- cons is a two-arg function but the parens are added and the result is an arity exception because it becomes (cons 42) which is invalid.

seancorfield04:02:58

Similarly, (-> x :k) becomes (:k x) (which is valid)

hindol04:02:50

Yes, I actually meant that. Don't know why I wrote it this way. It's technically incorrect.

seancorfield04:02:09

Parens are added whenever they are omitted πŸ™‚

hindol04:02:18

I mean every single thing without paren will be put in paren. For example, (-> [1 2 3] map square), map and square will be put in separate parens, which is wrong.

seancorfield04:02:09

Although (map [1 2 3]) is legal (it returns a transducer) πŸ™‚

seancorfield04:02:52

(it's not a useful transducer since [1 2 3] is not a reducing function)

hindol04:02:20

I am just bad with examples I guess, πŸ˜‚. I keep forgetting vectors are also fns.

seancorfield04:02:57

(-> [1 2 3] map square) => (square (map [1 2 3])) πŸ™ƒ

eagon06:02:01

Question related to Datomic Ions, but I think the answers are much more about the basics so asking here. In Ions you pass a handler function to either Lambda or http entry points, and the rest of system management is abstracted away. In particular, I wasn't sure where we could hook into system startup (basically whatever the equivalent of -main is), and saw that the provided ion-starter solved these initial configuration-like steps with memoize on client but was basically hitting the database every call to check if a starter dataset was loaded. I'm looking to use larger system management libraries like component/mount/integrant but I'm not sure where to call component/start . What are best practices here, and what are some patterns I could use? Can I rely on the idempotency of start in these libraries and basically call it on every request? I was thinking of just closing over an atom to return a handler that does a simple in-memory check like so:

(defn run-once [handler]
  (let [started (atom false)]
    (fn [& args]
      (if @started
        (apply handler args)
        (do 
          (println "system start functions called here")
          (reset! started true)
          (apply handler args))))))
Are there better/simpler solutions with delay or memoize? Am I missing something really basic?

Shima07:02:34

Hi I'm very new with clojurescript I download a website template and put it in the resource directory and now after lein trampoline run -m figwheel.main -b dev -r I can see the template in the browser but the repl won't work anymore, however, the only change is in the resources I also don't get any warning or exception Do you have any idea about the possible reasons? (The figwheel logs stop just before print clojurescript version)

Aviv Kotek12:02:29

silly Q but is there any way to convert KEY to INT. :1 -> 1 instead of converting to string?

ben13:02:34

It’s a bit of a loaded footgun but:

(-> :1 name Integer/parseInt)

Aviv Kotek13:02:12

Yea I want without the string convertion

AJ Jarosinski13:02:49

@USPQF75AS It looks like it’s stored as a String based on this source below, which means probably that the idea from @ben is the best https://github.com/clojure/clojure/blob/clojure-1.9.0/src/jvm/clojure/lang/Symbol.java#L40-L42

Aviv Kotek13:02:26

Yea that's what I thought, k thanks

craftybones14:02:59

Hello. I have the following macro, which works

(defmacro make-fn [name args body]
  `(fn ~name ~args ~body))

craftybones14:02:12

I can execute this from the repl as follows

craftybones14:02:38

(make-fn add [x y] (+ x y))

craftybones14:02:56

However, if I invoke make-fn from a function, the spec fails while macroexpanding fn

craftybones14:02:24

user=> (defn fn-maker [name args body] (make-fn name args body))
Syntax error macroexpanding clojure.core/fn at (form-init14866211691412444997.clj:1:33).
args - failed: vector? at: [:fn-tail :arity-1 :params] spec: :clojure.core.specs.alpha/param-list
args - failed: (or (nil? %) (sequential? %)) at: [:fn-tail :arity-n] spec: :clojure.core.specs.alpha/params+body

craftybones14:02:36

And this is while defining, not while calling.

craftybones14:02:52

It seems like fn, understandably, enforces its args to be a vector

craftybones14:02:59

Just trying to understand this a bit better. So the spec is invoked at defn time?

alexmiller14:02:20

it's validated during macroexpansion

alexmiller14:02:49

which is actually what it says there "syntax error macroexpanding clojure.core/fn"

craftybones14:02:12

Right. I am curious about fn being a macro. I know the same to be true of let as well. Both are listed as special forms which expand to fn* and let*

alexmiller14:02:44

you should probably treat that as implementation details

craftybones14:02:26

Someone I know is using instaparse to write a language and they are writing a bunch of macros which expands their language to runnable Clojure code

alexmiller14:02:36

you can turn off spec macro checking

alexmiller14:02:44

(but anyone would need to do that to use this)

craftybones14:02:03

Ok, thanks @alexmiller.

alexmiller14:02:13

or you could tweak that macro definition to be a vector

craftybones14:02:20

Oh that’s a good idea

alexmiller14:02:40

(defmacro make-fn [name args body]
  `(fn ~name [[email protected]] [email protected]))

alexmiller14:02:08

something like that (the body not being a splice quote was a bug), but depends a bit on what you're trying to do

craftybones14:02:17

No, this works. Thanks

Michael J Dorian21:02:39

Is spec a correctly sized hammer for this nail? All the simulated objects in my game have their state in a map, including function identifiers, and I need my code to yell at me if a new map is missing critical keys or if the functions it identifies choke on it's data when run. I could just do a series of checks, but if this is the correct use case for spec, I'll use that so I can get an understanding of what everyone's so excited about!

alexmiller21:02:57

seems like a possible match

Michael J Dorian21:02:51

Cool, I'll give it a go then simple_smile