Fork me on GitHub
#beginners
<
2019-01-26
>
jaihindh.reddy01:01:39

Can I do a defmethod based on runtime state from component / integrant?

jaihindh.reddy01:01:30

In other words, when is having defmethod not at top level justified, if at all?

hiredman01:01:41

you can dispatch on runtime state, you just pass it in

hiredman01:01:14

a defmethod mutates a multimethod and adds a method to it, and the only way to create a multimethod that clojure exposes is via defmulti, which creates a var containing a multimethod

hiredman01:01:48

so using defmethod, or defmulti outside of the global scope (not as a toplevel form) is at least questionable

shawx53801:01:11

how might one read a string of binary directly into a number?

shawx53801:01:37

I'm looking to turn an arbitrary block of ones and zeros into the corresponding number

shawx53801:01:08

I looked at Long.parseUnsignedLong, but I can't seem to call it

shawx53801:01:55

Okay, got it in Integer/parseInt

seancorfield02:01:33

@shawx538 This should work if you need larger numbers (Long/parseLong "10101010101" 2)

quieterkali04:01:49

hey guys, i am playing at trying to understand some clojure source code, and i need help to understand the or implementation. can you guys go through each line of the or body and explain it to me, please

quieterkali04:01:59

(defmacro or
  "Evaluates exprs one at a time, from left to right. If a form
  returns a logical true value, or returns that value and doesn't
  evaluate any of the other expressions, otherwise it returns the
  value of the last expression. (or) returns nil."
  {:added "1.0"}
  ([] nil)
  ([x] x)
  ([x & next]
      `(let [or# ~x]
         (if or# or# (or [email protected])))))

quieterkali04:01:03

i tried to evaluate ([] nil) in the repl but that throws an error

quieterkali04:01:31

for some how, i think be able to read the source code and understand it can help me to get a better understanding of clojure

john04:01:38

That has an implementation for 3 different "arities"

john04:01:10

Zero arity: ([] nil)

john04:01:40

1 arity: ([x] x)

john04:01:10

Does that much make sense? So far?

quieterkali04:01:30

just googled arities hehehehe

quieterkali04:01:12

arities = arguments?

john04:01:17

So yeah, four functions or macros you can provide any number of arity implementations. That there is a macro, so it's going to have some more complex syntax

john04:01:41

Right, but specifically the word arity is with regard to the number of arguments

john04:01:06

We say a thing has zero arity, two arity, or many arity

john04:01:24

If that much makes sense, what else seems mysterious about it still? The if? The let binding?

quieterkali04:01:55

look like you're in my thinkings

john04:01:49

A lot of the extra punctuation is there because it's a macro. Macros are functions that write other functions, like templates

quieterkali04:01:39

yeah i read that they are kind of functions but are not evaluated or something like that

quieterkali04:01:57

but i honestly didn't get to dig on them yet

john04:01:55

They're super powerful

quieterkali04:01:13

let [or# ~x] putting ~x into or#

john04:01:31

But easier to understand once you understand the syntax for functions

quieterkali04:01:34

but why not just x

quieterkali04:01:05

~ means what here?

quieterkali04:01:24

i think i understand a little bit functions

john04:01:00

Right, those are special characters for macros. ~ is an "unquote"

quieterkali04:01:08

functions defn function name args body

didibus04:01:28

(or 1 2) becomes:

(let [v 1]
  (if v
    v
    (or 2)))
If that helps

john04:01:54

That's a syntax quote

john04:01:55

Everything inside: `(inside stuff here)

quieterkali04:01:00

what else if i have (or false false false (prn foo))?

quieterkali04:01:42

what will be that be in the if call?

quieterkali04:01:55

ooooooh sorry

quieterkali04:01:09

you edited the answer

didibus04:01:32

Ya, I'm on my phone, so its hard to type πŸ˜‹ I edited it

didibus04:01:00

So if you have more things the else would be the rest

didibus04:01:24

(let [v 1]
  (if v
    v
    (or 2 3 false (print 23) true false)))

didibus04:01:42

And then it will recursively expand

didibus04:01:52

Into a bunch of nested if that are similar to this

john04:01:53

That or would return to nil from the last println, because it'll keep calling itself until it gets a truthy value or runs out of things

didibus04:01:37

Until you reach an else with a single element in the or like (or false) and that will call the one arity or, which just returns the value passed in

john04:01:50

Inside a quoted form, an unquote symbol will grab the thing from the outside, compiling environment.

quieterkali04:01:55

so (or [email protected]) will be this (or 2 3 false (print 23) true false)?

john04:01:31

Sorta like string interpolation

john04:01:55

But in this case recursive string interpolation

quieterkali04:01:35

sorry @john please show me the quoted and unqutoted form in the code i pasted please

quieterkali04:01:11

sorry for asking too much but really want to make sure i get what you are saying

didibus04:01:29

So (or 1 2 3) after all expansions becomes:

(let [v 1]
  (if v
    v
    (let [g 2]
      (if g
          g
          3))))

quieterkali04:01:32

Inside a quoted form, an unquote symbol will grab the thing from the outside, compiling environment.

john04:01:08

So like, in the or form:

(defmacro or
  ([] nil)
  ([x] x)
  ([x & next]
      `(let [or# ~x]                            ;; <- syntax quote starts on this line with the ` symbol
         (if or# or# (or [email protected])))))    ;; <- a syntax unquote starts on this one with the ~ symbol

john04:01:21

[email protected] is a "splicing unquote," which will remove the parenthesis from around whatever's being unquoted

john04:01:45

the # symbol attaches some extra metadata to the orvariable so that it does not clash with other instances of or variables that may be recursively defined, so that it doesn't clobber itself

john04:01:23

usage of the word "or" for that variable in the let binding is probably unhelpful from an understanding perspective

john04:01:41

It could just have easily been called x#

john04:01:54

or, not x

quieterkali04:01:59

is it possible to show me a snippet code of [email protected] in action please?

john04:01:34

y# perhaps, since x is already being used in the outside context, which would just add to the confusion πŸ˜†

quieterkali04:01:05

something like ([email protected] apply on something) ===> something else

john04:01:15

It's normally called from within a macro... and specifically, from within a form that is being syntax quoted

quieterkali04:01:04

yeah i just googled and found some reading about it πŸ™‚

quieterkali04:01:58

thank you very much @john and @didibus, you've taught me a lot in such a short time πŸ™‚

john04:01:59

also study the when macro:

(defmacro when
  [test & body]
  (list 'if test (cons 'do body)))

john04:01:45

that's building up the template in a different way

quieterkali05:01:03

that is exactly the one i was planning to learn after or πŸ˜„

john05:01:33

also check out if-not:

(defmacro if-not
  ([test then] `(if-not ~test ~then nil))
  ([test then else]
   `(if (not ~test) ~then ~else)))

john05:01:49

That may be an easier one to start off with

quieterkali05:01:03

ok, but i warn you that questions will come πŸ˜„

john05:01:05

Well there's plenty of folks around here willing to help

quieterkali05:01:19

πŸ˜„ just giving those tips about where to start looking help a lot

john05:01:20

Just remember, everything inside a () is a form. Everything inside a syntax quoted form ()` is a like a future form. It turns into a present form after being evaluated once. Anything unquoted within a quoted future form, will be injected into the future form from the present form.

john05:01:48

well... It's hard to show a syntax quote here πŸ™‚

john05:01:05

That's a syntax quoted form

john05:01:30

so, in the above if-not macro, test, then and else are all existing as their present values in the present macro form

john05:01:59

the if and the not, within the syntax quoted form, do not exist as present values... you can think of them like strings

john05:01:36

everything between the ` and the ~ is like a string. Everything inside the form or value to the right of the unquote symbol will be pulled out of the present form and written into the template, like concatenating present and future values together.

john05:01:33

so test, then and ~else are pulling the present values and pasting them into a string that will become a form that looks like an if statement with the test cond negated.

john05:01:34

(it's not actually a string, but you get the idea)

quieterkali05:01:20

@john πŸ‘:+1:πŸ˜€βœ”οΈ you're explanation did really help, i am going to keep it somewhere close and read it again again again again πŸ˜„

john05:01:55

Good deal, keep reading the code too, again and again and again πŸ™‚

quieterkali05:01:58

yeah i got the idea, the code make more sense now to me

seancorfield05:01:10

@john FYI, for single backticks:

`()

seancorfield05:01:20

(i.e., wrap it in triple backticks)

quieterkali06:01:35

(defmacro if-not
  "Evaluates test. If logical false, evaluates and returns then expr, 
  otherwise else expr, if supplied, else nil."
  {:added "1.0"}
  ([test then] `(if-not ~test ~then nil)) ====> so this line will end up calling this one (if (not ~test) ~then ~else) ?
  ([test then else]
   `(if (not ~test) ~then ~else)))

seancorfield06:01:07

(with else bound to nil)

quieterkali06:01:40

that is nice, i got to learn something new this night πŸ˜„

quieterkali06:01:50

but i1ve look for if implementation in clojure and didn't find one. so is the clojure if using the java one?

seancorfield06:01:21

if is a special form in Clojure, so it's built into the compiler.

quieterkali06:01:18

huummm sorry @seancorfield i don't know what you mean by that 😞

quieterkali06:01:34

than you πŸ˜„

seancorfield06:01:41

"special form" means a primitive within the language

seancorfield06:01:02

So you won't really find a definition, except in the documentation or deep in the source code of the compiler itself.

seancorfield06:01:42

(but that page shows just how small the core language really is -- everything else in Clojure is built on top of those special forms)

quieterkali06:01:34

thank you very much, i didn't know that πŸ˜„

quieterkali07:01:19

(defmacro when
     "Evaluates test. If logical true, evaluates body in an implicit do."
     {:added "1.0"}
     [test & body]
     (list 'if test (cons 'do body))) ===> (if test (do body))

(when true (prn "Maflany" (prn 1) (prn 2) (prn 3)))

=> (list 'if true (cons 'do (prn "Maflany" (prn 1) (prn 2) (prn 3))))

=> (if true (do (prn "Maflany" (prn 1) (prn 2) (prn 3))))

quieterkali07:01:42

did i got it right?

seancorfield07:01:57

Almost. Since a macro deals with code, it's as if the value of body was quoted: (list 'if true (cons 'do '(prn "Maflany" (prn 1) (prn 2) (prn 3)))) -- note the ' before the prn form.

seancorfield07:01:33

But, yeah, the end result is as if you had typed in that code (if true (do ...))

seancorfield07:01:19

The is at the heart of Clojure's (Lisp's) "code is data" mantra.

quieterkali07:01:54

but in the source code of when, body doesn't have ` 

quieterkali07:01:49

i mean it's not write `body there, but just body

quieterkali07:01:50

so why how comes body to become `body ? 

seancorfield08:01:29

@quieterkali I only meant in terms of your code substitution -- you wrote (list 'if true (cons 'do (prn "Maflany" (prn 1) (prn 2) (prn 3)))) but that's not the same as (list 'if true (cons 'do '(prn "Maflany" (prn 1) (prn 2) (prn 3))))

seancorfield08:01:56

The former would evaluate the (prn ...) form before making the list. The latter will leave it as code.

seancorfield08:01:43

With a macro, your arguments are code so they are substituted as-is -- as if they were quoted forms, rather than forms to be evaluated.

seancorfield08:01:57

It's a subtle point, but it's important with macros.

quieterkali02:01:56

hey @seancorfield, so you mean since my body was a form so it should had take quoted to not be evaluated so early, but is it was only a variable, a literal like 42 "string" or any other then he wouldn't need a quote. Am i right?

seancorfield03:01:02

Correct. Strings, numbers, keywords all evaluate to themselves

quieterkali04:01:22

Thank you very much πŸ˜„

sfyire13:01:19

I'm looking at the java-time clojure wrapper and they use this for their documentation:

(refer-clojure :exclude [range iterate format max min])
(use 'java-time)
how do I include the library behind a alias like
(datetime/max ...)
or
(datetime/local-date ...)
?

borkdude13:01:40

(require '[java-time :as datetime])

funyako.funyao15614:01:04

Hi, is there any way to run use-fixtures just once for the whole testing session? I want to do integration testing and starting/stopping for each ns seems like a bad idea (?). Actually I'm not sure about this, can someone give me some feedback.

borkdude14:01:07

global testing fixtures don’t exist in vanilla clojure.test, but https://github.com/circleci/circleci.test has it

borkdude14:01:42

I think they would be a nice addition

borkdude14:01:53

e.g. to instrument certain functions

borkdude14:01:31

for integration testing I use something different, just wrap run-tests with my own function, not using fixtures

funyako.funyao15614:01:29

That's actually a great idea. Thank you

dev63216:01:44

Hi guys! I have some problems with getting cider to work with clojurescript and figwheel and I must admit it's getting kind of frustrating. Would someone be able to help me?

dpsutton16:01:58

@dev632 I can try in #cider but I'm not at a computer

jaihindh.reddy18:01:57

My hiccup's rendering with weird characters for commas and quotes like this Γ’β‚¬β€œ. What did I do wrong? The data's coming from a mysql DB.

risinglight20:01:59

MySQL defaults to latin1 encoding where as the rest of the world usually assumes unicode/UTF-8 these days

dpsutton18:01:51

You've got an encoding issue I would think.

lain19:01:38

Hello everyone, could someone tell me is it possible to configure project with frontend and backend at same time? If it is, how can i do that?

dev63220:01:27

My problem in cider is that I can get cider to start an nrepl, but if I use figwheel as repl type it open the website, but then I have a prompt saying "STDIN:" in the minibuffer at the bottom. Inside that minibuffer I can interact with the clojurescript repl but I can't send any sexp from my core.cljs buffer in emacs to the figwheel repl.

dev63220:01:25

And if I use the newer figwheel-main repl type (and a project created with lein new figwheel-main) cider still opens up the website and tries to create a figwheel repl, but the last thing printed in the cider-repl is "Opening URL http://localhost:9500" and after that nothing happens.

dev63220:01:50

Also cider is always showing "not connected" in my modeline in emacs.