beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
lunik1 2021-05-19T00:43:45.056500Z

Ah I think I have it, should have been

(defne nevero [] ([] (nevero)))

2021-05-19T01:42:38.056700Z

Most likely you have evaled one in a namespace already and so now there was already an alias in that namespace.

✅ 1
pithyless 2021-05-19T05:47:33.056900Z

Usually, keyword namespaces are not meant to be programmatically manipulated and interpreted in "parts". This is a subject that comes up once in a while e.g. in clojure.spec discussions, but my understanding is that this is not something the Clojure Core team feels is a good practice, so you won't find a lot of clojure.core functions to manipulate the namespace as a hierarchy of segments. To not go against the grain, you can ask yourself if your request should be asking for the name of item :sword or simply should be asking for the :item.sword/name? The latter would make it unambiguous and no need for the monkeying around with strings; the former and writing some helper function to hide (keyword (str/join "." ["item" (name item)]) "name") is probably as good as it gets.

popeye 2021-05-19T06:46:37.057600Z

Does :use only to import java classes?

2021-05-19T07:11:29.057700Z

https://clojuredocs.org/clojure.core/use No, it is only for clojure namespaces.

popeye 2021-05-19T07:39:44.057900Z

@delaguardo I referred few documents , and I did not get when to use :require and :use

2021-05-19T07:41:01.058100Z

the only difference is that use also refer to each function from namespace.

(use 'clojure.string)
(join "," ["a" "b" "c"]) ;; => "a,b,c"
but with require you have to use fullyqualified function name
(require 'clojure.string)
(clojure.string/join "," ["a" "b" "c"])

popeye 2021-05-19T07:41:45.058300Z

what about require ?

2021-05-19T07:43:45.058600Z

usually, best practices of clojure suggesting to not use use but use require with :as alias modifier

☝️ 1
🙌 1
Aron 2021-05-19T09:42:13.063300Z

i have 42 lines in my :require and i would really like to use circular dependencies

1
Elliot Stern 2021-05-19T13:57:40.068600Z

What’s the most idiomatic way to thread a function if it exists - something like

(-> foo
  ...
  #(if sorter (sort sorter %) (identity %))
  ...)

raspasov 2021-05-21T01:18:44.158Z

I made some-as-> (like some-> and as-> combined). It will short-circuit on nil https://github.com/raspasov/alexandria-clj/blob/main/src/ss/core.cljc#L111

kennytilton 2021-05-23T14:56:50.271400Z

the "else" above is (identity %). My imagination fails me: how will that be different than %? Otherwise, your approach seems fine.

Elliot Stern 2021-05-19T13:58:03.069100Z

Is there something like when for this kind of usecase?

alexmiller 2021-05-19T13:59:13.069400Z

cond->

kennytilton 2021-05-23T15:02:21.271600Z

In a world like Common Lisp where sort is destructive we could use when sorter sort X knowing X will either get sorted or sail on untroubled as is, but not so with clojure.

alexmiller 2021-05-19T13:59:57.069900Z

well, kind of depends on the whole thing

Elliot Stern 2021-05-19T14:01:28.070300Z

this is the only conditional item, but there’s only like 4 things in the macro

alexmiller 2021-05-19T14:01:57.070500Z

could switch to as-> too

alexmiller 2021-05-19T14:02:30.071200Z

or lift it out into let

alexmiller 2021-05-19T14:03:35.072200Z

(let [f (if sorter (sort sorter %) (identity %))]
  (-> foo
    ...
    f
    ...)) 

☝️ 1
valerauko 2021-05-19T16:05:53.073Z

not sure if i asked this before, but is there a way to name a reify-produced class?

valerauko 2021-05-19T16:06:48.074300Z

just asking because when i have multiple things reified in the same namespace, it is impossible to tell from the stacktrace which one of them caused trouble

valerauko 2021-05-19T16:07:29.074700Z

would be nice if they could be named optionally like fns

2021-05-19T16:11:33.075700Z

you can customize toString and you can put it inside a named parent

user=> ((fn foo [] (reify Object (toString [_] "a foo"))))
#object[user$eval142$foo$reify__144 0x7fab4be7 "a foo"]

2021-05-19T16:12:04.076300Z

notice that foo shows up in the class name, and "a foo" shows up as the second half of the #object data

dpsutton 2021-05-19T16:13:44.076800Z

i don't see anything in a stacktrace that helps though

ghadi 2021-05-19T16:13:53.077100Z

reify is by definition unnamed

ghadi 2021-05-19T16:14:20.077600Z

well... uncontrolled classnames

dpsutton 2021-05-19T16:14:35.078200Z

(defprotocol Foo (foo [_]))
(foo (reify Object (toString [_] "custom") Foo (foo [_] (throw (ex-info "boom" {})))))
doesn't have that tostring message in the stacktrace, nor would i expect it

ghadi 2021-05-19T16:14:41.078400Z

the stacktrace however should exactly pinpoint any fault

2021-05-19T16:15:41.079900Z

@dpsutton the wrapping named function addresses the stack trace identifiability

2021-05-19T16:16:08.080500Z

that's why I used both the fn and toString

2021-05-19T16:25:48.083100Z

(ins)user=> (def frobber ((fn frobber [] (reify Object (toString [_] "a frobber") clojure.lang.IFn (invoke [_] (:frobbing-error))))))
#'user/frobber
(ins)user=> frobber
#object[user$frobber$reify__153 0x432034a "a frobber"]
(ins)user=> (frobber)
Execution error (IllegalArgumentException) at user/frobber$reify (REPL:1).
Wrong number of args passed to keyword: :frobbing-error
(ins)user=> *e
#error {
 :cause "Wrong number of args passed to keyword: :frobbing-error"
 :via
 [{:type java.lang.IllegalArgumentException
   :message "Wrong number of args passed to keyword: :frobbing-error"
   :at [clojure.lang.Keyword throwArity "Keyword.java" 98]}]
 :trace
 [[clojure.lang.Keyword throwArity "Keyword.java" 98]
  [clojure.lang.Keyword invoke "Keyword.java" 110]
  [user$frobber$reify__153 invoke "NO_SOURCE_FILE" 1]
...
@dpsutton @vale more complete example, showing how both the toString and the wrapping thunk help with readability

2021-05-19T16:27:34.083900Z

and accidentally even showing how it is especially useful in the repl where there's no source file or line number

2021-05-19T16:29:05.084800Z

it's taking advantage of the fact that reify inside an fn is an inner class of that fn (which we already established can be named)

ghadi 2021-05-19T16:29:30.085200Z

gotta focus on the problem statement

ghadi 2021-05-19T16:29:46.085600Z

"I can't tell which of the reifies is implicated in this stack trace"

ghadi 2021-05-19T16:30:19.086600Z

that should be determinable from the line numbers appearing in the trace

2021-05-19T16:30:26.086800Z

right, so if the desired thing is a readable name (like with fn), using a wrapping fn addresses that

2021-05-19T16:31:04.088200Z

I agree that line numbers help too, but as a workflow issue, I find it easier to go by human readable names I can search rather than line numbers

valerauko 2021-05-19T16:56:38.088700Z

yes you are of course right

valerauko 2021-05-19T16:56:41.089Z

it is not impossible

valerauko 2021-05-19T16:57:49.090300Z

but it would be way more simple to parse and understand if they were nameable even for such cosmetic purposes

valerauko 2021-05-19T16:58:41.091Z

i don't want to refer to the generated class by its name or anything

Joni Hiltunen 2021-05-19T18:06:37.092500Z

I wonder if it's possible to solve a circular dependency between 2 functions somehow? I'm trying to do this: https://gist.github.com/Sose/b07f44536f3e97fd1307b1edfa8b5840

alexmiller 2021-05-19T18:07:41.092700Z

use declare

Joni Hiltunen 2021-05-19T18:08:48.092900Z

thanks!

2021-05-19T18:25:56.093Z

a macro can make this approach easier to read

Lukas 2021-05-19T19:09:43.095Z

Huhu, I wrote a macro, and I get an error when try to put a number in a form

Unexpected error (ClassCastException) macroexpanding q at (src/lhrb/engine.clj:327:3).
class java.lang.Long cannot be cast to class clojure.lang.Named (java.lang.Long is in module java.base of loader 'bootstrap'; clojure.lang.Named is in unnamed module of loader 'app')
for some reason it works when I substitute the number with a symbol
;; does not work
(macroexpand
   '(q {:find [?num ?loc]
       :where [(gr-th ?num 1000)
               [?b :battle/attacker_size ?num]]}
       db))

;; does work
(def n 100)
(macroexpand
   '(q {:find [?num ?loc]
        :where [(gr-th ?num n)
               [?b :battle/attacker_size ?num]]}
       db))
I figured that this is probably a silly beginner mistake, so could maybe a wise person please enlighten me? 😋 Any help is greatly appreciated background: I wrote a micro-kanren implementation and try to give it a datomic flavored query api with the macro

dpsutton 2021-05-19T19:14:36.095500Z

wild stab, but i guess you look at each form to determine if it begins with a ??

Lukas 2021-05-19T19:15:00.096100Z

yes i do

ghadi 2021-05-19T19:15:09.096400Z

always look at your full stack trace *e

Lukas 2021-05-19T19:16:01.097400Z

Show: Project-Only All 
  Hide: Clojure Java REPL Tooling Duplicates  (0 frames hidden)

2. Unhandled clojure.lang.Compiler$CompilerException
   Error compiling src/lhrb/engine.clj at (331:3)
   #:clojure.error{:phase :macroexpansion,
                   :line 331,
                   :column 3,
                   :source "/home/lukas/projects/datahog/src/lhrb/engine.clj",
                   :symbol q}
             Compiler.java: 7023  clojure.lang.Compiler/macroexpand1
                  core.clj: 4012  clojure.core/macroexpand-1
                  core.clj: 4014  clojure.core/macroexpand
                  core.clj: 4014  clojure.core/macroexpand
                      REPL:  331  lhrb.engine/eval10264
                      REPL:  331  lhrb.engine/eval10264
             Compiler.java: 7181  clojure.lang.Compiler/eval
             Compiler.java: 7136  clojure.lang.Compiler/eval
                  core.clj: 3202  clojure.core/eval
                  core.clj: 3198  clojure.core/eval
    interruptible_eval.clj:   87  nrepl.middleware.interruptible-eval/evaluate/fn/fn
                  AFn.java:  152  clojure.lang.AFn/applyToHelper
                  AFn.java:  144  clojure.lang.AFn/applyTo
                  core.clj:  667  clojure.core/apply
                  core.clj: 1977  clojure.core/with-bindings*
                  core.clj: 1977  clojure.core/with-bindings*
               RestFn.java:  425  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   87  nrepl.middleware.interruptible-eval/evaluate/fn
                  main.clj:  437  clojure.main/repl/read-eval-print/fn
                  main.clj:  437  clojure.main/repl/read-eval-print
                  main.clj:  458  clojure.main/repl/fn
                  main.clj:  458  clojure.main/repl
                  main.clj:  368  clojure.main/repl
               RestFn.java:  137  clojure.lang.RestFn/applyTo
                  core.clj:  667  clojure.core/apply
                  core.clj:  662  clojure.core/apply
                regrow.clj:   20  refactor-nrepl.ns.slam.hound.regrow/wrap-clojure-repl/fn
               RestFn.java: 1523  clojure.lang.RestFn/invoke
    interruptible_eval.clj:   84  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:   56  nrepl.middleware.interruptible-eval/evaluate
    interruptible_eval.clj:  152  nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
                  AFn.java:   22  clojure.lang.AFn/run
               session.clj:  202  nrepl.middleware.session/session-exec/main-loop/fn
               session.clj:  201  nrepl.middleware.session/session-exec/main-loop
                  AFn.java:   22  clojure.lang.AFn/run
               Thread.java:  832  java.lang.Thread/run

1. Caused by java.lang.ClassCastException
   (No message)

ghadi 2021-05-19T19:16:30.098200Z

by default, the REPL presents a one or two line summary, but fuller information is available in the trace, including which line of your source file threw an exception

Lukas 2021-05-19T19:17:00.098300Z

(defn compile-where-clauses
  "transforms vector clauses into q-db queries
  e.g. [?a :age 10] => (q-db db ?a :age 10)"
  [clauses db]
  (->> clauses
       (map (fn [clause]
              (if (vector? clause)
                `(q-db ~db ~@clause)
                clause)))))

(defn find-lvars
  "finds and returns all unique logic-variables.
  A logic var begins with an '?'"
  [find where] ;; maybe decouple from concrete impl?
  (->> (into find where)
       (flatten)
       (filter
        (fn [s]
          (str/starts-with? (name s) "?")))
       (distinct)))

(defmacro q [{:keys [find where]} db]
  (prn &form)
  (prn &env)
  (let [;; test if vars in find clause are also in where clause
        lvars (find-lvars find where)
        where-compiled (compile-where-clauses where db)]
    `(let [~@(interleave
              lvars
              (map
               (fn [sym]
                 `(gensym ~(name sym)))
               lvars))]
       (run
         (reify-var ~@find)
         ~@where-compiled))))

Lukas 2021-05-19T19:17:30.099100Z

ah i see

ghadi 2021-05-19T19:17:38.099500Z

so, I am already going to qualify this ^ In the specific case of ClassCastExceptions and NullPointerExceptions, sometimes the JVM elides traces 🙂

ghadi 2021-05-19T19:17:55.100Z

(that is controllable)

Lukas 2021-05-19T19:19:32.101400Z

this is the output from *e

#error {
 :cause nil
 :via
 [{:type clojure.lang.Compiler$CompilerException
   :message "Unexpected error macroexpanding q at (/home/lukas/projects/datahog/src/lhrb/engine.clj:331:3)."
   :data #:clojure.error{:phase :macroexpansion, :line 331, :column 3, :source "/home/lukas/projects/datahog/src/lhrb/engine.clj", :symbol q}
   :at [clojure.lang.Compiler macroexpand1 "Compiler.java" 7023]}
  {:type java.lang.ClassCastException
   :message nil}]
 :trace
 []}

ghadi 2021-05-19T19:19:39.101700Z

right, elided -- normal traces are not empty vectors []

ghadi 2021-05-19T19:20:31.102700Z

somewhere in your macro you're asking for the name of a symbol, but calling it on a number (which are Longs in clojure)

Lukas 2021-05-19T19:20:58.103Z

okay thank you

Lukas 2021-05-19T19:21:55.104500Z

That helps I guess I can track it now down (there is one part where I call name)

ghadi 2021-05-19T19:21:56.104600Z

you can pass -XX:-OmitStackTraceInFastThrow to your REPL

ghadi 2021-05-19T19:22:24.105400Z

which would fill out the empty :trace []

ghadi 2021-05-19T19:22:57.106500Z

it's a speed thing. Prod code never throws ClassCastExceptions, so the JVM optimizes for not filling out full stack traces.

Lukas 2021-05-19T19:23:11.106700Z

🙏 ty soo much, very good input

Lukas 2021-05-19T19:24:26.108100Z

could you help and tell my how I pass -XX:-OmitStackTraceInFastThrow` to my repl? 🙈

Joni Hiltunen 2021-05-19T19:24:48.108700Z

good parsing library? I searched online and found https://github.com/Engelberg/instaparse but it hasn't been updated in a while. is it abandoned or is it just so finished that it hasn't needed any updates recently? I wanna parse a simple imperative language (for moving a turtle)

aengelberg 2021-05-20T19:56:58.154400Z

We’re still here and generally respond to important bug reports 🙂 Also I answer questions in #instaparse sometimes

Lukas 2021-05-19T19:24:50.108900Z

just typing in does not work

Lukas 2021-05-19T19:25:17.109100Z

In clojurespace libraries do not get updates when they are done

Lukas 2021-05-19T19:25:35.109300Z

your fine using this library

Joni Hiltunen 2021-05-19T19:25:41.109600Z

okay, thank you

Lukas 2021-05-19T19:29:57.110900Z

Anyways you guys rock, and thanks a lot for helping strangers on the internet you are great :hugging_face:

seancorfield 2021-05-19T19:33:58.111100Z

@djonih You’ll find a lot of Clojure libraries that haven’t been updated in ages — Clojure folks value stability and also tend to like libraries that solve one problem “completely” and therefore can be “done” and not need constant updates. It always looks strange to folks coming from language backgrounds where there is always a lot of “churn” on libraries.

seancorfield 2021-05-19T19:34:33.111300Z

We use Instaparse heavily at work for our custom search rules (driving 40+ online dating sites).

❤️ 1
Joni Hiltunen 2021-05-19T19:35:24.111500Z

@seancorfield thank you! should be good for my toy program then 😄

alexmiller 2021-05-19T19:38:32.112300Z

in the repl, (clojure.repl/pst *e) is often more readable than *e (and does some other useful things like eliding top frames related to error throwing)

💡 2
dpsutton 2021-05-19T19:40:55.113300Z

And -XX:-OmitStackTraceInFastThrow is a jvm option. You start a jvm with this option

💡 1
Lukas 2021-05-19T19:42:17.113600Z

🙏 Thanks a lot

caumond 2021-05-19T20:55:20.115300Z

I am really happy now to see a library with an old Last commit. I only have a doubt with dependencies. I guess an ideal library have very few dependencies but in most cases there are. For instance version of clojure clojurescript and reader. So what is your practise concerning these dependencies ? Do you update them manually ?

seancorfield 2021-05-19T21:01:48.115500Z

I usually don’t bother much about whatever version of tools.reader is pulled in these days. I have a top-level dependency for Clojure (or ClojureScript) so that takes precedence over whatever any libraries bring in (I’m using the CLI / deps.edn).

2021-05-19T22:05:24.116100Z

Any great libraries or repos for beginners to play around with to learn, particularly through projects?

2021-05-19T22:06:15.116800Z

I’d be very curious about any libraries that analyze quantitative data. Statistics is super interesting to me, but I’m interested in just about anything that’s fun to play with

lunik1 2021-05-19T23:44:12.121100Z

Is it preferable to use all and conde or *and and *or in core.logic ?

Jonas 2021-05-19T23:54:00.122100Z

Hey all, I was wondering if there is a way in Clojure to convert a function back into it's source string, as in

user=> (defn foo [] (println "foo"))
user=> (clj->str foo)
"(defn foo [] (println \"foo\"))"

2021-05-19T23:54:57.122300Z

no

2021-05-19T23:55:41.122900Z

sometimes you can look up the source (if it is still around via a file somewhere) via metadata on foo

🙏 1
2021-05-19T23:56:17.123600Z

I tend to prefer conde and usually use fresh with no lvars, but likely should be using all

2021-05-19T23:57:44.124100Z

user=> (doc source)
-------------------------
clojure.repl/source
([n])
Macro
  Prints the source code for the given symbol, if it can find it.
  This requires that the symbol resolve to a Var defined in a
  namespace for which the .clj is in the classpath.

  Example: (source filter)
nil
user=>