Fork me on GitHub
#beginners
<
2019-08-17
>
ho0man12:08:31

Hi everyone, I have a weird question. I was writing a macro and encountered this : ('flsakjf 12) => nil flsakjf is some symbol why does it return nil ?

andy.fingerhut12:08:52

symbols are similar to keywords in Clojure, in that when you put them in first position like a function call, they "look themselves up" in a collection like a map, or a set, given as an argument.

andy.fingerhut12:08:03

e.g. (:foo {:foo 1 :bar 2}) returns 1

andy.fingerhut12:08:16

Looking up keys in non-map things returns nil

shin14:08:20

hi, trying to build a currency converter in re-frame so far it works in one direction (eur->yen) if I enter stuff in the euro field, I would like to have it both ways though, i.e. if I enter anything in the euro field it shows me the amount in yen and vice versa one direction makes sense to me, but I get confused about what :value and :on-change should be when thinking about doing it in both ways...

valtteri16:08:07

Making two inputs intertwined like this is quite difficult and making it work 100% across all possible browsers may require a lot of work. If this is a real project I suggest that you output the result of the conversion to a label rather than in another input field. If this is just for fun then I'd suggest storing both text value and "calculated numeric value" in to the app-db and overriding the input value with a calculated value only when the other input has sane values. Maybe something like this:

[:input
      {:value     (or eur-val eur-input)
       :on-change #(re-frame/dispatch [::calc-yen (-> %  .-target .-value)])}]
(re-frame/reg-event-db
 ::calc-yen
 (fn [db [_ eur-input]]
   (let [eur-val (parse-num eur-input)]
     (-> db
         (assoc :eur-input eur-input)
         (assoc :yen-val (when eur-val (* eur-val eur->yen-rate)))))))
And similar input and event for the other direction

shin14:08:07

thank you! I'll try it out that way

shabbir.r.bhojani15:08:17

Hi all. Why does ((first '(+ 1 2)) 3 4) return 4 and not 7?

jaihindhreddy15:08:17

(first '(+ 1 2)) returns the symbol +

schmee15:08:48

@shabbir.r.bhojani good question! the reason is that (first '(+ 1 2)) returns the symbol +, not the function. since symbols are functions in Clojure (just like keywords), you are calling (+ 3 4) with + as a symbol, which is meant for associative lookups (compare (= ('+ {'+ 1}) 1)), where the second argument is the value to return if the mapping is not found

shabbir.r.bhojani15:08:54

What needs to be put in (first '(? 1 2)) to make it return the function instead of the symbol?

schmee15:08:35

canโ€™t be done, quoted forms always return literals

shabbir.r.bhojani15:08:50

Hm. Ok. How do I convert the literal to the function afterwards?

dpsutton15:08:18

((first (list + 1 2 3)) 3 4)

schmee15:08:31

with resolve ๐Ÿ™‚

user=> (resolve '+)
#'clojure.core/+

dpsutton15:08:31

(resolve '+)

mfikes17:08:06

Another way:

(first `(~+ 1 2))

shabbir.r.bhojani02:08:43

@ I just got around to trying this and ((first '(~+ 1 3)) 2 4) produced the error `Execution error (ClassCastException) at clojure-test-project.core/eval1600 (form-init15410744857529963710.clj:1). class clojure.lang.PersistentList cannot be cast to class clojure.lang.IFn (clojure.lang.PersistentList and clojure.lang.IFn are in unnamed module of loader 'app')`. What did I do wrong?

mfikes02:08:15

The quote should be a "backtick", called "syntax-quote".:

((first `(~+ 1 3)) 2 4)

mfikes02:08:43

The idea here is that you can then use the ~ character to "unquote" things.

mfikes02:08:47

`(~+ 1 2)
is essentially the same as
(list + 1 2)

jaihindhreddy15:08:54

Which when called in function position tries to look itself up in 3 with the default 4, hence returning 4

jaihindhreddy15:08:09

@schmee you beat me to it ๐Ÿ™‚

schmee15:08:04

to get the expected result, you can do ((first (list + 1 2)) 3 4)

chepprey15:08:42

"tries to look itself up in 3" can you flesh that out a bit? (for noob brains)

shabbir.r.bhojani15:08:15

Expects the 3 to be a map and looks up the key + in it.

jaihindhreddy15:08:12

keywords and symbols when used as functions try to look themselves up in the first argument return nil if there is no second argument, and the second argument otherwise.

chepprey15:08:32

so when 3 is regarded as a map, which it clearly isn't, the behavior is to just return nil, instead of throwing some kind of typing exception?

jaihindhreddy15:08:50

Try these in your REPL:

user=> (:a {:a 42})
42
user=> (:a {:b 42})
nil
user=> (:a {:b 42} 100)
100
Same with symbols

jaihindhreddy15:08:31

Yes. Many other things in Clojure just return nil instead of throwing.

chepprey15:08:36

jdm-try-clj.core> (:a 3)
nil
jdm-try-clj.core> 

jaihindhreddy15:08:43

Here's the relevant code for keywords: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Keyword.java#L136 this delegates to RT.get which in this case uses RT.getFrom which returns null instead of throwing.

joshlemer19:08:06

What does it mean when functions or other things are surrounded by *? as in *print-readably* in

(defn print
  "Prints the object(s) to the output stream that is the current value
  of *out*.  print and println produce output for human consumption."
  {:added "1.0"
   :static true}
  [& more]
    (binding [*print-readably* nil]
      (apply pr more)))

andy.fingerhut19:08:47

It is a naming convention that the var is 'dynamic', meaning it can be dynamically bound per thread using binding.

andy.fingerhut19:08:17

There is also a compiler warning if you name something like that, but do not make it dynamic, so in this case it is a slightly more enshrined naming convention than most.

andy.fingerhut19:08:10

A bit more info on what a dynamic Var means here: https://clojure.org/reference/vars

joshlemer19:08:10

Thank you @andy.fingerhut

hans37821:08:02

hmm this is weird:

{:type java.lang.IllegalArgumentException
   :message No matching method withRegion found taking 1 args for class com.amazonaws.services.s3.AmazonS3ClientBuilder
   :at [clojure.lang.Reflector invokeMatchingMethod Reflector.java 154]}
But two of those methods exist: https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/client/builder/AwsClientBuilder.html#withRegion-java.lang.String-

schmee22:08:35

not a solution to your problem (sorry!), but if youโ€™re doing AWS with Clojure you may want to check out https://github.com/cognitect-labs/aws-api!

schmee22:08:07

also, could you post the call you are making the gives you the error?

hans37822:08:22

i use that lib for most of my aws-interaction

hans37822:08:24

but it doesn't do a specific thing i need, which is creating pre-signed S3 urls: https://github.com/cognitect-labs/aws-api/issues/5

schmee22:08:39

ahh, makes sense ๐Ÿ‘

iagwanderson22:08:36

I'm trying to use cljs-ajax to perform a request from my re-frame event to my localhost web server. However, it seems like the uri parameter cannot specify a port. only the endpoint.

(POST
    ""
    {:format :json
     :params {:value (:value db)}
     :handler #(re-frame/dispatch [::update-database %])
     :error-handler #(re-frame/dispatch [::error-handler %])})
this example returns status 0. Seems like my endpoint cannot be reach. If I change the uri to /save it calls some html page. I think I have to make a previous setup to let the library knows the whole url address of my backend service. But I could not find where I specify that

iagwanderson23:08:38

{:uri , :last-method POST, :last-error [0], :last-error-code 6, :debug-message Http response at 400 or 500 level, :status 0, :status-text Request failed., :failure :failed}

iagwanderson23:08:42

the whole error message