beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
flowthing 2021-04-11T06:09:48.352800Z

https://www.youtube.com/watch?v=096pIlA3GDo

➕ 1
Oliver 2021-04-11T06:48:14.355300Z

When I start a REPL with lein repl in my project directory I see the following error: #error { :cause Could not locate clj_json/core__init.class, clj_json/core.clj or clj_json/core.cljc on classpath. Please check that namespaces with dashes use underscores in the Clojure file name. :via [{:type clojure.lang.Compiler$CompilerException :message Syntax error compiling at (myproject/core.clj:1:1). :data #:clojure.error{:phase :compile-syntax-check, :line 1, :column 1, :source myproject/core.clj} :at [clojure.lang.Compiler load Compiler.java 7648]} {:type <http://java.io|java.io>.FileNotFoundException :message Could not locate clj_json/core__init.class, clj_json/core.clj or clj_json/core.cljc on classpath. Please check that namespaces with dashes use underscores in the Clojure file name. Any hint what I am doing wrong here? deps.edn looks like this: { :deps { clj-json/clj-json {:mvn/version "0.5.3"} } }

pavlosmelissinos 2021-04-11T06:54:50.355700Z

deps.edn is for clojure cli lein repl needs a project.clj file, does your project have one? Either that or add a :dev alias to your deps.edn and start a repl with clj -A:dev

Oliver 2021-04-11T07:19:00.358600Z

I kind of understand. 😉 Sorry, I am just beginning with clojure. Would it be easier to start the repl with clj? I am trying to start a repl on the command line and then connect to it from inside spacemacs. If I use lein repl I get back a port and this works fine (besides the error). But I don't get any port information back if I start the repl with clj.

pavlosmelissinos 2021-04-11T07:51:03.362900Z

Ah, I see. Since you feel comfortable with lein, you can create a project.clj file (deps.edn is clj specific). It's been years since I last used lein so I can't help you if you have more specific questions but here are the instructions: https://github.com/technomancy/leiningen/blob/stable/doc/TUTORIAL.md#projectclj Personally I don't care about decoupling my REPLs from emacs so I'm using clj+cider

👍 1
Oliver 2021-04-11T08:03:39.363400Z

Thanks, Pavlos. I also found some tutorial from @jr0cket here https://practicalli.github.io/clojure/clojure-tools/install/community-tools.html that I will read through.

👍 1
practicalli-john 2021-04-11T08:30:51.364100Z

The CLj doesn't start an nrepl server (network connection to the repl) by default, unlike Leiningen which does.

Oliver 2021-04-11T08:38:45.364300Z

@jr0cket I guess I need to run through your tutorial once more to understand all this. I used to program in CL years ago and am very interested in Clojure, but the tooling is quite confusing for me, too many things to understand at once.

practicalli-john 2021-04-11T08:58:25.364500Z

If you do not need an interactive REPL command line, i.e. you are only evaluating Clojure code in Spacemacs buffers, then you can use

clojure -M:middleware/cider-clj
If you also want an interactive REPL in the terminal as well as evaluating in Spacemacs, then use
clojure -M:repl/rebel-nrepl
This uses the rebel readline repl which is a much richer REPL UI experience than the default clojure or clj, but the code evaluates just the same Both commands will show the nREPL port number once the nREPL server is listening. cider-connect should find the nrepl port automatically anyway

practicalli-john 2021-04-11T09:02:54.364800Z

I also have Spacemacs specific content, which uses Clojure cli tools here: https://practicalli.github.io/spacemacs/clojure-repl/connect-to-repl.html

practicalli-john 2021-04-11T09:03:19.365Z

Feel free to ask me questions about this if its not clear, there is always room for improvement

practicalli-john 2021-04-11T09:18:38.365600Z

To connect from the command line to a REPL aready running, either in Spacemacs or another terminal session, use the command

clj -Sdeps '{:deps {nrepl/nrepl {:mvn/version "0.8.3"}}}' -M -m nrepl.cmdline --connect --host localhost --port 46587
Replace values for --host and --port as requried. Use SPC b m to see the nrepl host and port in the *message* buffer. I'll add an alias for this too, as it may be useful for connecting to remote REPL's

👍 1
Oliver 2021-04-11T09:25:26.365800Z

Cool, I think it works now. Thank you, John!

👍 1
practicalli-john 2021-04-11T13:25:48.371200Z

I've simplified the REPL aliases section (hopefully), with a clearer distinction as to where to use each alias (terminal, editor, remote). I've also added two aliases for connecting to a remote REPL (eg. a repl run on a remote server or repl run from the editor jack-in process) https://github.com/practicalli/clojure-deps-edn#repl-terminal-ui

Zaymon 2021-04-11T06:55:32.356500Z

Hi, I’m just starting with Clojure. I’m struggling to think about how I should compose handlers. Is there a more idiomatic way to run validation, if it’s okay perform some side-effect and then return an appropriate response?

(def Letter
  [:map
   {:title "Letter"}
   [:id uuid?]
   [:recipient uuid?]
   [:sender uuid?]
   [:content string?]])

(defn validate-letter [letter] (me/humanize (m/explain Letter letter)))

(defn send-letter
  "Handler to send a letter to another user"
  [{{{:keys [letter]} :body} :parameters}]

  (let [letter-with-id (assoc letter :id (java.util.UUID/randomUUID))]

    (if-let [errors (validate-letter letter-with-id)]
      {:status 400
       :body {:errors errors}}

      ;; Where do I persist this thing to the database?

      {:status 200
       :body {:letter letter-with-id}})))
Coming from F# where everything is mostly done with chaining monads I’m struggling to get my head around how to express workflows with an Ok path and an Error path.

pavlosmelissinos 2021-04-11T06:55:41.356600Z

@oliver.heck Check out https://github.com/seancorfield/dot-clojure for inspiration

dharrigan 2021-04-11T07:26:56.359Z

I see you're using reitit and malli?

Zaymon 2021-04-11T07:27:12.359100Z

Sure am 🙂

dharrigan 2021-04-11T07:28:54.359300Z

There is the #reitit and #malli channels, but for now, I can tell you what I do. Malli and Retiti also use Muunjata for validation (part of the suite). If you define a spec, and it fails the spec (i.e., validation), an appropriate error will be returned to the client. However, for more business-oriented validation, I have my own excpetion middleware

dharrigan 2021-04-11T07:29:02.359500Z

that I place in the chain

dharrigan 2021-04-11T07:29:44.359700Z

then deeper down in the layers if I encounter an error, like some business contraint violation, I throw and let the exception handler catch, log out to Sentry, but also format a lovely response back to the client.

Zaymon 2021-04-11T07:30:29.359900Z

Aha. Okay that would be great to move the validation up a layer. I’ll look into it

dharrigan 2021-04-11T07:30:40.360100Z

I should extend my simple github example to use some validation

dharrigan 2021-04-11T07:30:53.360300Z

but for now, here's a quick example:

dharrigan 2021-04-11T07:31:21.360500Z

<https://github.com/dharrigan/startrek>

dharrigan 2021-04-11T07:31:37.360700Z

today, you've given me reason to add in some simple validation 🙂

Zaymon 2021-04-11T07:32:26.360900Z

Sweet I’ll look out for the changes too.

Zaymon 2021-04-11T07:32:29.361100Z

Thanks!

dharrigan 2021-04-11T07:32:32.361300Z

in my business application, I have this:

dharrigan 2021-04-11T07:33:10.361500Z

:middleware [swagger/swagger-feature
                        muuntaja/format-middleware
                        (exceptions/exception-middleware app-config)
                        parameters/parameters-middleware
                        coercion/coerce-exceptions-middleware
                        coercion/coerce-request-middleware
                        coercion/coerce-response-middleware]}}))

dharrigan 2021-04-11T07:33:23.361700Z

notice the (exceptions/exceptions-middleware ....)

dharrigan 2021-04-11T07:33:28.361900Z

that's my own middleware handler

Zaymon 2021-04-11T07:33:54.362100Z

Did you just need more control over how exceptions were presented?

dharrigan 2021-04-11T07:34:23.362300Z

yes, I wanted to give back to the client lots more details, and a nicely crafted response.

✅ 1
Hagenek 2021-04-11T10:03:17.369500Z

Hi everyone, hope you are having a nice sunday. I am struggling to understand this destructuring. It reminds me of the syntax used when we require namespaces. Is it basically to get a variable flash which the value associated with the :flash key on the request map, and also keeping the request variable as the map provided as an argument to the home-page function?

(defn home-page [{:keys [flash] :as request}]
  (layout/render
   request
   "home.html"
   (merge {:messages (db/get-messages)}
          (select-keys flash [:name :message :errors]))))

pavlosmelissinos 2021-04-11T10:24:36.369700Z

Yes, that's another way of saying:

(defn home-page [request]
  (layout/render
   request
   "home.html"
   (merge {:messages (db/get-messages)}
          (select-keys (:flash request) [:name :message :errors]))))

😃 1
raspasov 2021-04-11T11:22:47.370100Z

@georghagen exhaustively useful guide to Clojure destructuring 🙂 https://clojure.org/guides/destructuring

☝️ 1
roelof 2021-04-11T11:58:51.370800Z

just jumping in to say hello and I hope everyone is still healty

🙃 3
rakyi 2021-04-11T14:56:40.372Z

there is #exercism

Dave Suico 2021-04-11T15:19:49.373500Z

Hi guys, does anyone know how to fix an error message like this when u try to install polylith as a dependency? "Error building classpath. Manifest type not detected when finding deps for polyfy/polylith in coordinate"

roelof 2021-04-11T15:46:31.373600Z

thanks

2021-04-11T16:42:32.376700Z

I’m trying to figure out when to use the ! suffix on functions. Do I use it on any function that is impure? The docs aren’t super clear to me as they reference functions that “are not safe in STM transactions” which I’m not clear about. Also, does everything that calls this function also get the bang? Here’s my sequence of functions in question for background:

(defn get-register!
  "return the byte contents of a register (action)"
  [bus port register]
  (let [address (get-in registers [port register])] ;; lookup register address
    (smbus/read-byte bus address)))                 ;; return the value there

(defn get-registers!
  "return the byte contents of both :a and :b registers (action)"
  [bus register]
  {:a (get-register! bus :a register)
   :b (get-register! bus :b register)})

(defn get-int-registers!
  "Return all the registers needed to deduce what changed related to an
  interrupt occurence (action)"
  [bus]
  (do ;; order of reads is important
    (def intf (get-registers! bus :intf))
    (def intcap (get-registers! bus :intcap))
    (def gpio (get-registers! bus :gpio))
    {:intf intf :intcap intcap :gpio gpio}))

practicalli-john 2021-04-12T16:52:47.413Z

I use it on functions that actually do a mutation or major side-effect. I don't use the ! for functions that call functions that do the mutation.

👍 1
2021-04-12T19:38:57.440600Z

Thanks everyone. I’ve decided not to propagate the exclamation mark but I’ll have to think more about the first read because it’s not idempotent, it will actually cause the next read to be different. I may use it there.

dpsutton 2021-04-11T16:59:26.378400Z

clojure uses the STM in loading libraries and possibly other functions, so it is true that every time i use clojure i use the STM. Outside of that though, I've never directly used it in code that i've consumed or code that i've written. I wouldn't use the STM's conventions in naming affect your naming choices. That being said, people often use ! as a suffix when writing mutating impure functions. Add it as you like

👍 2