Fork me on GitHub
#beginners
<
2020-08-06
>
Vladyslav Sitalo04:08:59

I’m facing a weird behavior with str (cljs). I observe the following difference: (str "n" " blah") -> "n blah" (str "\n" " blah") -> "\nblah" (in the second case the space are removed (??) is that an expected behavior or a bug?

Vladyslav Sitalo04:08:28

interesting. wonder what version is it running

Vladyslav Sitalo04:08:45

mine is “1.10.773”

Vladyslav Sitalo04:08:30

cljs.user=> *clojurescript-version*
"1.8.40"

Vladyslav Sitalo05:08:08

so seems like a bug in a more recent version?

dpsutton05:08:51

how are you starting your repl?

clj -A:cljs -m cljs.main -re node -r
ClojureScript 1.10.597
cljs.user=> (str "\n" "          blah")
"\n          blah"

dpsutton05:08:45

works for me on 597

dpsutton05:08:42

and on 773 as well

dpsutton05:08:46

clj -A:cljs -m cljs.main -r
ClojureScript 1.10.773
cljs.user=> (str "\n" "        blah")
"\n        blah"
cljs.user=>

okwori05:08:22

Yeah seen it now, doesn't on 764 for me also(via cursive remote repl with figwheel)

okwori05:08:06

I think it is seeing it as an escape character, \e for eg. returns Unsupported escape character: \e. exception

Vladyslav Sitalo03:08:32

hmm, I think it has something to do with Cursive repl

Vladyslav Sitalo03:08:06

when I run this in it - this happens, but for the same version of clojur in raw repl it doesn’t

Jim Newton10:08:10

What is the correct way to effectively do the following? (assoc old-map :a 10 :b 20 :c 30) If I have two maps old-map and new-map for which new-map has value {:a 10 :b 20 :c 30} .. I.e., I want any new values in new-map to be added to the result and for any colliding keys, the value from new-map should have precedence. If I use concat I get a sequence of pairs, not a map, according to https://clojuredocs.org/clojure.core/concat

dharrigan10:08:22

(merge old-map new-map)

👍 6
gekkostate11:08:13

Hi everyone! Quick deployment question for you. Currently, we are deploying our app by creating an uberjar, uploading it to the server and using something like systemd to run it while nginx fronts it. I was wondering if someone could point me to a resource which explains how one might do this process automatically? An annoying problem is when we have a small (or big, both are equally annoying :P) change, we implement a fix and then we have to go through the process of compiling the uberjar and uploading and so on. Thanks for your time!

Tzafrir Ben Ami12:08:04

Do you mean a development tool like Jenkins? (Or GitHub Actions)? You would still need to write some scripts probay but there is no reason not to automate deployment

gekkostate12:08:27

Yes, Jenkins looks like the right thing. I’m a complete novice with this (not even familiar with the terms).

Tzafrir Ben Ami12:08:37

If you are running on GitHub, I would check GitHub Actions first (just for the sake of avoiding consuming a new tool). There are some available options https://github.com/marketplace?type=actions&amp;query=deploy for deployment directly to Azure or AWS (depending on where you host your server). Jenkins is also a very commonly used tool, but you will need to “learn” it first

Tzafrir Ben Ami12:08:03

I would also recommend adding your JAR in a Docker container instead of deploy it directly to your server

gekkostate14:08:01

Ok amazing, thank you! I’ll check this out. We’re deploying to a digitalocean droplet.

noisesmith14:08:49

A good term to research is "Continuous Integration" - it's a general category of tool that can create a new deployable artifact (and run tests. create downloadable artifacts etc. etc.) out of your repo commits. Eg. a github project can use circleci to create a new uberjar and deploy it to staging for every push to the prod branch, with a notification going to slack reporting on success or failure on completioin.

👍 3
noisesmith14:08:23

then, you can have a pushbutton deploy of the same artifact to prod with jenkins

noisesmith14:08:11

I disagree about docker - if you don't have native dependencies, an uberjar is simpler and less overhead and more secure.

gekkostate15:08:40

Great, thanks @U051SS2EU for pointing me in the right direction!

jumar16:08:50

You don’t have to run your container as root. With JAR you also have access to a potentially richer set of features and vulnerabilities of the host (depends on your VM/host configuration). I see docker as additional layer that should improve security of the system. Disclaimer: I’m not a huge proponent of (mis-)using docker just genuinely interested in why you think it’s less secure

jumar17:08:09

Oh, so that’s more about trusting 3rd party images/dependencies? I feel we sort of do that as well with maven dependencies (although their power is probably more limited)

jumar17:08:52

Also by JVM limiting permissions you mean it doesn’t give you full C-like access to the host OS? (though native code can still do anything)

noisesmith17:08:19

it's not just third party deps - it's the amount of damage a third party could do by replacing or adulterating an artifact

noisesmith17:08:07

the jvm also allows blocking specific classes (including the ones used for native access)

noisesmith17:08:51

but then again, realistically, with the sort of "devops" model everyone uses today, there are bigger and easier targets

Neil Ashton12:08:30

Reading lots of code from codebases that are representative of their language’s community norms, best practices, and successes seems like a good way to work towards fluency in a language. (A colleague of mine has been doing this with Go lately, reading the Kubernetes source and suchlike.) What are some Clojure projects that would make for good reading material in this way?

Shako Farhad12:08:29

That is a great question. I am also interested in that!

Neil Ashton13:08:03

I wonder if this is a particularly hard question for languages intended to be used the way Clojure is. The language was designed to be great for “information systems programming”, and I’d assume that most of the successful examples of that sort of system are enterprise applications in private repositories. So while you could probably just read the source code for key libraries like core.async and learn a lot about what well-written Clojure looks like, you wouldn’t necessarily learn what it looks like to use Clojure to build the kind of systems it’s claimed to excel at from doing that.

Shako Farhad13:08:34

One thing I can recommend is to check out the conduit real world app: https://github.com/gothinkster/realworld

👍 3
Shako Farhad14:08:26

Here is also a great Conduit real world app that is not in the list above. This one is clojurescript + react native. :) https://github.com/flexsurfer/conduitrn

Cris B23:08:54

I've asked this question in the community a couple of times. One concrete suggestion I got was https://github.com/mtgred/netrunner. Here's another one I came across via a podcast I heard: https://github.com/lipas-liikuntapaikat/lipas. I confess I haven't really dived into either yet, so I don't know how representative they are of 'best practices', but they are both real production code. With Rust or Go you'd be spoilt for choice. I'm not sure why there seem to be few open source large real-world Clojure projects.

Cris B02:08:19

Seen mentioned elsewhere here on Clojurians today, the Defold game editor: https://github.com/defold/defold/tree/dev/editor/src/clj/editor. Not the most typical Clojure use (a JavaFX app), but might be of interest.

Shako Farhad08:08:39

There is one more big project that I know of. It is a react native application with ios, android and desktop support. https://github.com/status-im/status-react

3
jumar20:08:37

And thanks for linking defold! I ran CodeScene analysis of the project just for fun and here are files/content statistics:

Cris B00:08:47

@U06BE1L6T - I remember downloading & having a play with the defold editor back when it was open sourced. I was considering clojure as my next language to learn & wanted to see what people were doing with it. Cool project & one of the best examples of a 'real' app using JavaFX I've come across.

Aviv Kotek13:08:20

what is an idiomatic way to trigger some method after another one ends successfully? I can have an atom and use add-watch to trigger the method if state changed, not sure if it's the right way. basically I want my web application to fire some method after a handler finishes it jobs correctly, I do not want to call the method from the handler itself,

Aviv Kotek13:08:15

want to separate handlers with other tasks, and learn some new tricks as well :)

Tzafrir Ben Ami14:08:08

You can use a middleware, also those are usually used to add additional functionality to your handlers and not to call a different method

Steiner14:08:02

anyone know how to use require, I have forgotten it for a long time

dpsutton14:08:35

(doc require)

Steiner14:08:36

can you give me an example about require as io?? thank you

dharrigan14:08:51

(require '[ :as io])

dpsutton14:08:52

(require '[ :as io])

dpsutton14:08:01

too quick 🙂

Steiner14:08:02

thank you both

Steiner14:08:42

how can I do to write a data into a file?

Steiner14:08:53

can someone help me out??

dharrigan14:08:58

If you want something a bit more low level, this might suffice

Steiner14:08:45

is that all? how do I load it?

dharrigan14:08:03

you can use slurp to load in data if you like

Steiner14:08:47

are you sure it will work when written data is binary but not string?

noisesmith15:08:03

to be clear, slurp and spit do not work on binary data

Steiner07:08:02

any methods usefule??

noisesmith12:08:43

look at what the http://clojure.java.io namespace provides (eg. io/copy) - eg. you can use io/copy to write a byte[] onto an output-stream

noisesmith12:08:57

it's not as simple for input though, since our byte-arrays are fixed length

noisesmith12:08:46

this is the easiest way I know of to put a binary file into an array:

(require '[ :as io])
(import ( ByteArrayOutputStream))

(let [o (ByteArrayOutputStream.)]
  (-> (str (System/getenv "HOME") "/blah.jpg")
      (io/file)
      (io/copy o))
  (.toByteArray o))

noisesmith12:08:29

io/copy promises to close the inputstream it makes from the file

dharrigan14:08:24

Yup, it can read in an array of bytes

noisesmith15:08:43

if you are referring to slurp, this is not safe, slurp and spit are for strings not binary

dharrigan19:08:21

Yup, of course 🙂 I failed to clarify to use the reader and writer directly.,

awcot14:08:13

Hey guys, I'd like to use clojure(/script) in order to create a static website for myself. I'd like a hot-reloading style workflow wherein I can build out the site's HTML & CSS using hiccup & garden in a manner similar to react's styled components. I then wish to be able to build and output the site into a public directory similar to how Gatsby and other static site generators work. I think existing clojure static site generators such as cryogen[0] and stasis[1] could be used to solve the second problem, but I've yet to find a nice CSS workflow. Are hiccup and garden sufficient for this? If not, would you be able to recommend any further libraries/approaches I could incorporate. Many thanks! [0] https://github.com/cryogen-project/cryogen [1] https://github.com/magnars/stasis

herald11:08:09

There are some wrappers around Garden if you're looking for something more similar to styled components: https://github.com/roosta/herb https://github.com/Jarzka/stylefy

Steiner14:08:58

eh, when using map to print something, it always return coll of nil element, is there any method like foreach in Scheme, which doesn't return any value??

Darin Douglass14:08:31

look at the do* group of fns. doseq seems to fit your description well

Steiner15:08:47

here I just want to get a matched regex value in a string, but not a list, is there any function I can use?

Steiner15:08:07

and how can I find a function acts like readdir ??

noisesmith15:08:23

@steiner3044 run! is precisely like foreach if I recall my scheme

noisesmith15:08:40

(run! println coll) prints each item in coll on a line, returns nil

Jim Newton15:08:49

What should I do If I get an Unhandled clojure.lang.Compiler$CompilerException

Jim Newton15:08:12

should I try to isolate it and file a bug report? Or should I just fix the error in my code and continue along?

noisesmith15:08:17

you can use *e to see the details

noisesmith15:08:49

usually it's a problem in your code, but the *e will have a lot of detail to determine the nature of the problem

Jim Newton15:08:00

I have the complete error message in the emacs window:

Jim Newton15:08:00

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

2. Unhandled clojure.lang.Compiler$CompilerException
   Error compiling src/clojure_rte/dfa.clj at (238:21)
   #:clojure.error{:phase :macro-syntax-check,
                   :line 238,
                   :column 21,
                   :source
                   "/Users/jnewton/Repos/clojure-rte/src/clojure_rte/dfa.clj",
                   :symbol for}
             Compiler.java: 7009  clojure.lang.Compiler/macroexpand1
             Compiler.java: 7092  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6789  clojure.lang.Compiler/analyze
             Compiler.java: 6745  clojure.lang.Compiler/analyze
             Compiler.java: 3104  clojure.lang.Compiler$MapExpr/parse
             Compiler.java: 6797  clojure.lang.Compiler/analyze
             Compiler.java: 6745  clojure.lang.Compiler/analyze
             Compiler.java: 3888  clojure.lang.Compiler$InvokeExpr/parse
             Compiler.java: 7108  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6789  clojure.lang.Compiler/analyze
             Compiler.java: 6745  clojure.lang.Compiler/analyze
             Compiler.java: 6120  clojure.lang.Compiler$BodyExpr$Parser/parse
             Compiler.java: 6436  clojure.lang.Compiler$LetExpr$Parser/parse
             Compiler.java: 7106  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6789  clojure.lang.Compiler/analyze
             Compiler.java: 7094  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6789  clojure.lang.Compiler/analyze
             Compiler.java: 6745  clojure.lang.Compiler/analyze
             Compiler.java: 6120  clojure.lang.Compiler$BodyExpr$Parser/parse
             Compiler.java: 5467  clojure.lang.Compiler$FnMethod/parse
             Compiler.java: 4029  clojure.lang.Compiler$FnExpr/parse
             Compiler.java: 7104  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6789  clojure.lang.Compiler/analyze
             Compiler.java: 7094  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6789  clojure.lang.Compiler/analyze
             Compiler.java:   38  clojure.lang.Compiler/access$300
             Compiler.java:  596  clojure.lang.Compiler$DefExpr$Parser/parse
             Compiler.java: 7106  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6789  clojure.lang.Compiler/analyze
             Compiler.java: 6745  clojure.lang.Compiler/analyze
             Compiler.java: 7180  clojure.lang.Compiler/eval
             Compiler.java: 7131  clojure.lang.Compiler/eval
                  core.clj: 3214  clojure.core/eval
                  core.clj: 3210  clojure.core/eval
    interruptible_eval.clj:   91  nrepl.middleware.interruptible-eval/evaluate/fn
                  main.clj:  414  clojure.main/repl/read-eval-print/fn
                  main.clj:  414  clojure.main/repl/read-eval-print
                  main.clj:  435  clojure.main/repl/fn
                  main.clj:  435  clojure.main/repl
                  main.clj:  345  clojure.main/repl
               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:  155  nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
                  AFn.java:   22  clojure.lang.AFn/run
               session.clj:  190  nrepl.middleware.session/session-exec/main-loop/fn
               session.clj:  189  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.IllegalStateException
   Can't pop empty vector

     PersistentVector.java:  470  clojure.lang.PersistentVector/pop
     PersistentVector.java:   22  clojure.lang.PersistentVector/pop
                   RT.java:  751  clojure.lang.RT/pop
                  core.clj: 1474  clojure.core/pop
                  core.clj: 4641  clojure.core/for/to-groups/fn
                  core.clj:  944  clojure.core/reduce1
                  core.clj: 4639  clojure.core/for/to-groups
                  core.clj: 4708  clojure.core/for
                  core.clj: 4624  clojure.core/for
                  AFn.java:  165  clojure.lang.AFn/applyToHelper
                  AFn.java:  144  clojure.lang.AFn/applyTo
                  Var.java:  705  clojure.lang.Var/applyTo
             Compiler.java: 6992  clojure.lang.Compiler/macroexpand1
             Compiler.java: 7092  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6789  clojure.lang.Compiler/analyze
             Compiler.java: 6745  clojure.lang.Compiler/analyze
             Compiler.java: 3104  clojure.lang.Compiler$MapExpr/parse
             Compiler.java: 6797  clojure.lang.Compiler/analyze
             Compiler.java: 6745  clojure.lang.Compiler/analyze
             Compiler.java: 3888  clojure.lang.Compiler$InvokeExpr/parse
             Compiler.java: 7108  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6789  clojure.lang.Compiler/analyze
             Compiler.java: 6745  clojure.lang.Compiler/analyze
             Compiler.java: 6120  clojure.lang.Compiler$BodyExpr$Parser/parse
             Compiler.java: 6436  clojure.lang.Compiler$LetExpr$Parser/parse
             Compiler.java: 7106  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6789  clojure.lang.Compiler/analyze
             Compiler.java: 7094  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6789  clojure.lang.Compiler/analyze
             Compiler.java: 6745  clojure.lang.Compiler/analyze
             Compiler.java: 6120  clojure.lang.Compiler$BodyExpr$Parser/parse
             Compiler.java: 5467  clojure.lang.Compiler$FnMethod/parse
             Compiler.java: 4029  clojure.lang.Compiler$FnExpr/parse
             Compiler.java: 7104  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6789  clojure.lang.Compiler/analyze
             Compiler.java: 7094  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6789  clojure.lang.Compiler/analyze
             Compiler.java:   38  clojure.lang.Compiler/access$300
             Compiler.java:  596  clojure.lang.Compiler$DefExpr$Parser/parse
             Compiler.java: 7106  clojure.lang.Compiler/analyzeSeq
             Compiler.java: 6789  clojure.lang.Compiler/analyze
             Compiler.java: 6745  clojure.lang.Compiler/analyze
             Compiler.java: 7180  clojure.lang.Compiler/eval
             Compiler.java: 7131  clojure.lang.Compiler/eval
                  core.clj: 3214  clojure.core/eval
                  core.clj: 3210  clojure.core/eval
    interruptible_eval.clj:   91  nrepl.middleware.interruptible-eval/evaluate/fn
                  main.clj:  414  clojure.main/repl/read-eval-print/fn
                  main.clj:  414  clojure.main/repl/read-eval-print
                  main.clj:  435  clojure.main/repl/fn
                  main.clj:  435  clojure.main/repl
                  main.clj:  345  clojure.main/repl
               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:  155  nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
                  AFn.java:   22  clojure.lang.AFn/run
               session.clj:  190  nrepl.middleware.session/session-exec/main-loop/fn
               session.clj:  189  nrepl.middleware.session/session-exec/main-loop
                  AFn.java:   22  clojure.lang.AFn/run
               Thread.java:  832  java.lang.Thread/run

dpsutton15:08:41

Caused by java.lang.IllegalStateException
   Can't pop empty vector

noisesmith15:08:53

a macro popped an empty vector during expansion - unless that macro is part of clojure.core it's not a clojure bug

Jim Newton15:08:06

When I print *e, I get this

Jim Newton15:08:06

clojure-rte.core> *e
#error {
 :cause "Can't pop empty vector"
 :via
 [{:type clojure.lang.Compiler$CompilerException
   :message "Syntax error macroexpanding for at (/Users/jnewton/Repos/clojure-rte/src/clojure_rte/dfa.clj:238:21)."
   :data #:clojure.error{:phase :macro-syntax-check, :line 238, :column 21, :source "/Users/jnewton/Repos/clojure-rte/src/clojure_rte/dfa.clj", :symbol for}
   :at [clojure.lang.Compiler macroexpand1 "Compiler.java" 7009]}
  {:type java.lang.IllegalStateException
   :message "Can't pop empty vector"
   :at [clojure.lang.PersistentVector pop "PersistentVector.java" 470]}]
 :trace
 [[clojure.lang.PersistentVector pop "PersistentVector.java" 470]
  [clojure.lang.PersistentVector pop "PersistentVector.java" 22]
  [clojure.lang.RT pop "RT.java" 751]
  [clojure.core$pop invokeStatic "core.clj" 1474]
  [clojure.core$for$to_groups__6291$fn__6293 invoke "core.clj" 4641]
  [clojure.core$reduce1 invokeStatic "core.clj" 944]
  [clojure.core$for$to_groups__6291 invoke "core.clj" 4639]
  [clojure.core$for invokeStatic "core.clj" 4708]
  [clojure.core$for invoke "core.clj" 4624]
  [clojure.lang.AFn applyToHelper "AFn.java" 165]
  [clojure.lang.AFn applyTo "AFn.java" 144]
  [clojure.lang.Var applyTo "Var.java" 705]
  [clojure.lang.Compiler macroexpand1 "Compiler.java" 6992]
  [clojure.lang.Compiler analyzeSeq "Compiler.java" 7092]
  [clojure.lang.Compiler analyze "Compiler.java" 6789]
  [clojure.lang.Compiler analyze "Compiler.java" 6745]
  [clojure.lang.Compiler$MapExpr parse "Compiler.java" 3104]
  [clojure.lang.Compiler analyze "Compiler.java" 6797]
  [clojure.lang.Compiler analyze "Compiler.java" 6745]
  [clojure.lang.Compiler$InvokeExpr parse "Compiler.java" 3888]
  [clojure.lang.Compiler analyzeSeq "Compiler.java" 7108]
  [clojure.lang.Compiler analyze "Compiler.java" 6789]
  [clojure.lang.Compiler analyze "Compiler.java" 6745]
  [clojure.lang.Compiler$BodyExpr$Parser parse "Compiler.java" 6120]
  [clojure.lang.Compiler$LetExpr$Parser parse "Compiler.java" 6436]
  [clojure.lang.Compiler analyzeSeq "Compiler.java" 7106]
  [clojure.lang.Compiler analyze "Compiler.java" 6789]
  [clojure.lang.Compiler analyzeSeq "Compiler.java" 7094]
  [clojure.lang.Compiler analyze "Compiler.java" 6789]
  [clojure.lang.Compiler analyze "Compiler.java" 6745]
  [clojure.lang.Compiler$BodyExpr$Parser parse "Compiler.java" 6120]
  [clojure.lang.Compiler$FnMethod parse "Compiler.java" 5467]
  [clojure.lang.Compiler$FnExpr parse "Compiler.java" 4029]
  [clojure.lang.Compiler analyzeSeq "Compiler.java" 7104]
  [clojure.lang.Compiler analyze "Compiler.java" 6789]
  [clojure.lang.Compiler analyzeSeq "Compiler.java" 7094]
  [clojure.lang.Compiler analyze "Compiler.java" 6789]
  [clojure.lang.Compiler access$300 "Compiler.java" 38]
  [clojure.lang.Compiler$DefExpr$Parser parse "Compiler.java" 596]
  [clojure.lang.Compiler analyzeSeq "Compiler.java" 7106]
  [clojure.lang.Compiler analyze "Compiler.java" 6789]
  [clojure.lang.Compiler analyze "Compiler.java" 6745]
  [clojure.lang.Compiler eval "Compiler.java" 7180]
  [clojure.lang.Compiler eval "Compiler.java" 7131]
  [clojure.core$eval invokeStatic "core.clj" 3214]
  [clojure.core$eval invoke "core.clj" 3210]
  [nrepl.middleware.interruptible_eval$evaluate$fn__2448 invoke "interruptible_eval.clj" 91]
  [clojure.main$repl$read_eval_print__9068$fn__9071 invoke "main.clj" 414]
  [clojure.main$repl$read_eval_print__9068 invoke "main.clj" 414]
  [clojure.main$repl$fn__9077 invoke "main.clj" 435]
  [clojure.main$repl invokeStatic "main.clj" 435]
  [clojure.main$repl doInvoke "main.clj" 345]
  [clojure.lang.RestFn invoke "RestFn.java" 1523]
  [nrepl.middleware.interruptible_eval$evaluate invokeStatic "interruptible_eval.clj" 84]
  [nrepl.middleware.interruptible_eval$evaluate invoke "interruptible_eval.clj" 56]
  [nrepl.middleware.interruptible_eval$interruptible_eval$fn__2474$fn__2478 invoke "interruptible_eval.clj" 155]
  [clojure.lang.AFn run "AFn.java" 22]
  [nrepl.middleware.session$session_exec$main_loop__2575$fn__2579 invoke "session.clj" 190]
  [nrepl.middleware.session$session_exec$main_loop__2575 invoke "session.clj" 189]
  [clojure.lang.AFn run "AFn.java" 22]
  [java.lang.Thread run "Thread.java" 832]]}
clojure-rte.core> 

Jim Newton15:08:36

I'm not using any of my macros in this code.

noisesmith15:08:43

so the *e reveals it was inside for

dpsutton15:08:16

to_groups__6291$fn__6293 invoke "core.clj" 4641] you probably have a function called to-groups

noisesmith15:08:25

notice how the contents of *e are clearer and more detailed than what emacs provides

Jim Newton15:08:27

looks like it's trying to expand the macro for

Jim Newton15:08:54

Here's the function I'm trying to compile:

noisesmith15:08:57

and as @dpsutton points out, it looks like to-groups has a bad for inside it

Jim Newton15:08:05

(defn complete
  "Render complete the given Dfa.
  If it is already complete, then simply return it,
  otherwise compute a new Dfa which has been completed, but
  adding a sink state if necessary and add at most one transition
  per state to the sink state."
  ([dfa]
   (let [incomplete (find-incomplete-states dfa)]
     (if (empty? incomplete)
       dfa
       (complete dfa incomplete))))
  ([dfa incomplete]
   (let [sink-state (or (first (find-sink-states dfa))
                        (let [sink-id (first (filter (fn [id]
                                                       (not ((:states dfa) id))) (range)))]
                          (map->State :index sink-id
                                      :accepting false
                                      :transitions (list [:sigma sink-id]))))]
     (make-dfa dfa {:states
                    (for [:let [current-states (states-as-seq dfa)
                                extended-states (if (member sink-state current-states)
                                                  current-states
                                                  (conj current-states sink-state))]
                          q extended-states                          
                          ]
                      [(:index q) (if (member q incomplete)
                                    (let [existing-labels (map first (:transitions q))
                                          new-label (if (empty? existing-labels)
                                                      :sigma
                                                      `(~'and :sigma (~'not (~'or ~@existing-labels))))]
                                      
                                      (map->State
                                       (assoc q
                                              :transitions (conj (:transitions q)
                                                                 [new-label (:index sink-state)])))))])}))))

noisesmith15:08:39

yeah, :let before any other clauses is the likely issue here- that' s super weird

noisesmith15:08:46

how would for decide how many times to run that let?

Jim Newton15:08:52

I'm not calling to-groups directly anyway.

noisesmith16:08:35

@jimka.issy I can replicate your error:

user=> (for [:let [x 0] y (range 10)] [x y])
Syntax error macroexpanding for at (REPL:1:1).
Can't pop empty vector

noisesmith16:08:51

you need some binding before :let

Jim Newton16:08:31

Ah. so it is a bug in the for macro. It should probably, check its assumption rather than emitting a compiler exception, I'd guess.

noisesmith16:08:42

think about what for tries to do here - as it does the recursive unwrap, it needs some input driving the :let calls, there's no input to be found if let comes first

noisesmith16:08:51

it's not a bug in for, it is a bug in your code

noisesmith16:08:47

there are many places where clojure gives a proximate cause in an error message rather than a root cause, and the general policy is not to try to find root causes for errors and let programmers find them

Jim Newton16:08:54

Sorry, but It is a bug in for, for is assuming the first entry is not :let and not checking that assumption.

noisesmith16:08:32

starting with :let doesn't even have a coherent possible meaning

Adrian Smith16:08:50

I think this is more a java question but I'm using bb, hoping to use it's transit support: https://github.com/borkdude/babashka/blob/ef06175678e421c99e870de9cb3b39a927ba7c9f/test-resources/babashka/transit.clj What would I need to do to read transit from standard in?

Jim Newton16:08:51

and that causes a compiler exception. Ok, its easy to fix once I see it. but at the very least I should get an error such as cannot-expand-macro...

noisesmith16:08:45

yeah - I don't mean to be hostile here, I'm just trying to articulate my own explanation for these behaviors (there are many places the clojure compiler behaves this way)

noisesmith16:08:57

in general, my observation is that if the clojure compiler has a choice between a higher level description of a cause, and a proximate immediate cause, you'll typically see the latter

noisesmith16:08:08

though over time (especially with spec) we see more pre-checking

noisesmith16:08:30

if for ever has a spec in clojure.spec, it should definitely include in its spec that :let can't be the first clause

👍 3
noisesmith16:08:54

oh, and btw. @dpsutton - to-groups is a helper function inside the definition of for itself

(defmacro for
  "List comprehension. Takes a vector of one or more..."
  {:added "1.0"}
  [seq-exprs body-expr]
  (assert-args
     (vector? seq-exprs) "a vector for its binding"
     (even? (count seq-exprs)) "an even number of forms in binding vector")
  (let [to-groups (fn [seq-exprs]
                    (reduce1 (fn [groups [k v]]
                              (if (keyword? k)
                                (conj (pop groups) (conj (peek groups) [k v]))
                                (conj groups [k v])))
                            [] (partition 2 seq-exprs)))

noisesmith16:08:17

there's assert-args here already, I guess an assertion could be made that (first seq-args) isn't :let

👍 3
dpsutton16:08:30

yeah i was looking for the source and couldn't find it

dpsutton16:08:33

and then work beckoned

Jim Newton16:08:10

I guess the first arg should neither be :let, nor :when, nor :while ???

Jim Newton16:08:22

same for doseq ?

dpsutton16:08:20

yeah. put your let above it if needed

dpsutton16:08:42

i think i remember hearing about a ticket for this and rich declined to act on it saying just do it correctly (if i remember)

noisesmith16:08:03

that sounds like how rich would respond to such a ticket

borkdude16:08:16

@sfyire let me check for you

❤️ 3
borkdude16:08:28

@sfyire This works for me:

$ echo '[{"a":1}]' | jet --from json --to transit | bb '(transit/read (transit/reader System/in :json))'
[{"a" 1}]

👍 3
borkdude16:08:50

Alternatively you can also just use jet to convert transit to edn