This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-08-24
Channels
- # announcements (26)
- # babashka (9)
- # beginners (63)
- # calva (2)
- # chlorine-clover (22)
- # cider (2)
- # cljsrn (8)
- # clojure (36)
- # clojure-europe (36)
- # clojure-italy (5)
- # clojure-nl (76)
- # clojure-spec (9)
- # clojure-uk (8)
- # clojurescript (39)
- # conjure (24)
- # cursive (19)
- # data-science (1)
- # datascript (10)
- # datomic (1)
- # emacs (2)
- # events (5)
- # figwheel-main (9)
- # fulcro (21)
- # graalvm (1)
- # helix (5)
- # jobs (1)
- # jobs-discuss (1)
- # kaocha (1)
- # leiningen (4)
- # meander (2)
- # off-topic (22)
- # re-frame (16)
- # reitit (3)
- # rewrite-clj (75)
- # rum (1)
- # sci (51)
- # shadow-cljs (110)
- # tools-deps (16)
- # vrac (9)
- # xtdb (23)
what's a preferred library method for formatting long floating point numbers and or currency strings? i'm seeing a lot of choices and am wondering if there is something most people choose?
the JDK has an extensive library built into it for both of these
java.text.NumberFormat/java.text.DecimalFormat are good classes to look at - both of these have support for locale-specific formatters and custom stuff
hi, quick question please, I’m trying to use memoize with :ttl following example from https://github.com/clojure/core.memoize/wiki/Ttl but when (require '[clojure.core.memoize :as memo])
I got file not found , not sure what did I miss? thanks
e.g., this works well without require any thing…
(def m-fib
(memoize (fn [n]
(condp = n
0 1
1 1
(+ (m-fib (dec n)) (m-fib (- n 2)))))))
But when I try to put in :ttl, it can’t find the namespace…
memoize
is a built-in (`clojure.core`) function.
In order to use the Contrib libraries, such as clojure.core.memoize
you need to add them to you dependencies in your project.
Are you use lein
or Clojure CLI (with deps.edn
).
For lein
you need [org.clojure/core.memoize "1.0.236"]
in your :dependencies
vector; for CLI you need org.clojure/core.memoize {:mvn/version "1.0.236"}
in your :deps
map.
thanks @U04V70XH6, all good now, didn’t notice the difference btw built-in function and Contrib libraries
I'm working with XML and was considering using multimethods with dispatch based on tag name. I have several tags/types that share the same schema but have different names in various messages. Would something like this be the right way to create a common handler for those tags?
(derive :ns/a :common/thing)
(derive :ns/b :common/thing)
(defmulti parse-element :tag)
(defmethod parse-element :common/thing
[element]
...)
I would pull the body implementation of parse-element as a defn for any shared implementations and have the defmultis call that before using derive
Is there a shortcut to make a map out of some identifiers/values; say: this that those
-> {:this this :that that :those those}
?
This is one way, maybe someone has a simpler version:
(into {} (mapv (juxt keyword identity) ['this 'that 'those]))
According to http://purelyfunctional.tv, this should fail silently:
(async/go (throw (RuntimeException. "Hello")))
However, when I try it, I get a stack-trace. Why?Exception in thread "async-dispatch-4" java.lang.RuntimeException: Hello
at core_async_playground.errors$eval16095$fn__16096$state_machine__13197__auto____16097$fn__16099.invoke(form-init855929826269882431.clj:1)
at core_async_playground.errors$eval16095$fn__16096$state_machine__13197__auto____16097.invoke(form-init855929826269882431.clj:1)
at clojure.core.async.impl.ioc_macros$run_state_machine.invokeStatic(ioc_macros.clj:973)
at clojure.core.async.impl.ioc_macros$run_state_machine.invoke(ioc_macros.clj:972)
at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invokeStatic(ioc_macros.clj:977)
at clojure.core.async.impl.ioc_macros$run_state_machine_wrapped.invoke(ioc_macros.clj:975)
at core_async_playground.errors$eval16095$fn__16096.invoke(form-init855929826269882431.clj:1)
at clojure.lang.AFn.run(AFn.java:22)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
#object[clojure.core.async.impl.channels.ManyToManyChannel 0x77ac7cd6 "clojure.core.async.impl.channels.ManyToManyChannel@77ac7cd6"]
I tried removing all the content in my .lein/profiles.clj
and I still got an error stack trace.
this exception is not thrown
(try (async/go (throw (RuntimeException. "Hello"))) (catch RuntimeException e (prn "!!!")))
you can try to silence it and you will see that this exception is returned from the channelThanks! The more I play around with core.async, the more it feels like "I don't know, and I don't wanna know" XD
correction: it is thrown but in another thread
But is the reason it is shown to throw something that Clojure has become updated or what? I do not understand why multiple sources say it should fail silently when it does not 🙂
it is shown only in repl. as an example:
(def x (async/go (throw (RuntimeException. "Hello"))))
the repl will show result of expression. in that case it would be ’#x
or something similar
so your sources right but requires a little bit more information about “fail”
“fail” here means “unexpected result” and “silent” — if that happens deep in call-stack the only way to notify caller - examine the result
Okay, I will have to play around with it some more to understand. In a leiningen project this also shows an error on the command line (`$ lein run`):
(defn -main [& args]
(let [x (async/go (throw (RuntimeException. "Hello")))]))
(That is, not in the REPL).The exception is printed to stderr by the default exception handler of the ThreadGroup that go blocks are using. You can override that by using Thread/setDefaultUncaughtExceptionHandler
Thanks to you too! Now I understand much better.
I have this piece of code in a go-block
:
(if (< val (@store :last-found))
;cleanup like close channel and such
)
Is there a way to ensure only one thread enters that if?You can create an atom which every task increments when it starts and decrements it after it finishes. Only enter the cleanup piece of code if the atom is zero. Another option is, if you run all your tasks in go blocks or threads, is use the facts they return channels, then write code which waits for takes from all tasks to complete (meaning they're done). Then wait for that code to complete. You're guaranteed to have it complete only after all tasks have finished.
Thanks!
Toy example:
(require '[clojure.core.async :as a :refer [go chan <! <!! >! >!! thread]])
(defn task [args]
(Thread/sleep 500)
(println args)
args)
(defn drain
[ch]
(go
(loop []
(when-let [x (<! ch)]
(recur)))))
(time (<!! (drain (a/merge (map (fn [x] (go (task x))) (range 32))))))
Note that the go-blocks thread pool has only 8 threads by default, so the above code will take ~2seconds to run
hi again, a question about error handling please, how do you do it when doing filter? e.g I have 2 vectors and want to filter one based on elements of the other like this:
(def tmsall [{:givenName nil :surname nil :email "[email protected]"}
{:givenName "Alice" :surname "Spring" :email ""}
{:givenName "Bob" :surname "Summer" :email "[email protected]"}
{:givenName "Carol" :surname "Autumn" :email "[email protected]"}
{:givenName nil :surname nil :email "[email protected]"}
{:givenName "Danny" :surname "Winter" :email "[email protected]"}
])
(def tslack ["Bob Best Summer" "Alice Spring"])
(try (filter (fn [m] (some (fn [s]( and (clojure.string/includes? s (:givenName m))
(clojure.string/includes? s (:surname m)))) tslack))
tmsall)
(catch Exception e (str "exception: " (.getMessage e))))
the clojure.string/include? will throw java.lang.NullPointerException
, I tried the try…catch above but not seems to work. And second question, if I just want to skip such Exception and run the filter with the rest of the elements, is it possible to do that? Thanksfilter
returns a lazy seq so it won't throw until that is later realized
you probably want to move the try/catch into the fn (or better, test for nil)
and you could easily add another filter to just ones with both a :givenName
and a :surname
I guess that’s why people never use try…catch with lazy seq return functions, that makes sense…, I just try putting the try/catch in the fn, and yes it catch the exception, interestingly, those nil elements also added to the final filtered elements… @dpsutton I was trying to use includes? as some of them have middle name/strange other name formats 🙂 … anyway, thanks @alexmiller, @dpsutton
How to refer to dev ns in comment blocks? for example when using component
(comment
(fn-call dev/system additional arg))
if the dev
namespace has been loaded into the REPL (and has the system
var at the time of evaluation) I think dev/system
should be accessible. Maybe someone else knows otherwise?
in my current REPL I created a namespace called dev with (def system "hi")
, then from a separate namespace eval'd
(comment
(prn dev/system))) => "hi"
and it worksi use this from reloaded template
(ns dev
"Tools for interactive development with the REPL. This file should
not be included in a production build of the application.
Call `(reset)` to reload modified code and (re)start the system.
The system under development is `system`, referred from
`com.stuartsierra.component.repl/system`.
See also "
(:require
[ :as io]
[clojure.java.javadoc :refer [javadoc]]
[clojure.pprint :refer [pprint]]
[clojure.reflect :refer [reflect]]
[clojure.repl :refer [apropos dir doc find-doc pst source]]
[clojure.set :as set]
[clojure.string :as string]
[clojure.test :as test]
[clojure.tools.namespace.repl :refer [refresh refresh-all clear]]
[com.stuartsierra.component :as component]
[com.stuartsierra.component.repl :refer [reset set-init start stop system]]
[{{main-ns}}]))
;; Do not try to load source code from 'resources' directory
(clojure.tools.namespace.repl/set-refresh-dirs "dev" "src" "test")
(defn dev-system
"Constructs a system map suitable for interactive development."
[]
(component/system-map
;; TODO
))
(set-init (fn [_] (dev-system)))
i can refer to dev/system in repl prompt but not in comment blocksI don't know Cursive, but with my editor that type of evaluation just sends the s-expression to the REPL like a copy/paste almost. What happens if you run require
from your comment before trying to eval the system variable? (comment (require 'dev) (dev/system ...))
Hey team, noob question -- how would you debug this? Context: I am trying to upload a file to google cloud. I look at https://googleapis.dev/java/google-cloud-storage/latest/com/google/cloud/storage/Bucket.html#create-java.lang.String-java.io.InputStream-com.google.cloud.storage.Bucket.BlobWriteOption...- And try to replicate it:
(def bucket (-> (StorageClient/getInstance) .bucket)
;; #object[com.google.cloud.storage.Bucket 0x4f155e75 "Bucket{name=journaltogether.appspot.com}"]
(def input-stream (FileInputStream. (:tempfile file)))
;; #object[java.io.FileInputStream 0x59d8712 "java.io.FileInputStream@59d8712"]
And now I try:
(.create bucket "foooo.png" input-stream "image/png" (into-array Storage$BlobWriteOption []))
This tells me:
No matching method create found taking 4 args for class com.google.cloud.storage.Bucket
Buut, it does seem to have these:
--
How could I debug further?Clojure is dynamic and doesn’t have the type information. There are four overloads for this method but clojure needs to figure out which of those four to invoke. If you type hint your args you can give clojure more information so that it can choose which of the four to call.
You might be able to get away with just hinting ^
but you might also need to hint the fourth argument which is a bit trickier/less obvious.
(defn upload-att [{:keys [filename ^String content-type tempfile] :as att}]
(let [bucket (.bucket (StorageClient/getInstance))
^String blob-name (str (UUID/randomUUID)
"/"
filename)
^InputStream input-stream (FileInputStream. tempfile)
^Storage$BlobWriteOption options (into-array Storage$BlobWriteOption [])]
(.create
bucket
blob-name
input-stream
content-type
options)))
I typed all of these guys, but it still seems to be having trouble. My intuition is that I typed something incorrectly. maybe options
?Aha!
(defn upload-att [{:keys [filename content-type tempfile] :as att}]
(let [bucket (.bucket (StorageClient/getInstance))
blob-name (str (UUID/randomUUID)
"/"
filename)
input-stream (FileInputStream. tempfile)
options (into-array Bucket$BlobWriteOption [])]
(.create
bucket
^String blob-name
^InputStream input-stream
^String content-type
options)))
Did the trick. Thanks for the help team!