Fork me on GitHub
#beginners
<
2021-09-23
>
Benjamin08:09:37

How do I say with spec "The thing should have keys x , y and I don't care what the values are" ?

delaguardo08:09:08

(s/def ::x any?)

(s/def ::y any?)

(s/keys :req-un [::x ::y])

practicalli-johnny09:09:30

If the hash-map definitely should have those keys present, then it would be req rather than req-un for optional keys

delaguardo10:09:55

Optional keys defined as :opt-un and :opt.

practicalli-johnny10:09:55

Ah, I got un/qualified key names (`:req-un` and :`req` ) mixed up with optional keys, :`opt`, thanks for the correction.

delaguardo10:09:56

(require '[clojure.spec.alpha :as s])

(s/def ::x any?)

(s/def ::y any?)

(s/def ::unqualified-keys (s/keys :req-un [::x] :opt-un [::y]))

(s/def ::qualified-keys (s/keys :req [::x] :opt [::y]))

(s/valid? ::unqualified-keys {::x 1 ::y 2}) ; => false because :x is required
(s/valid? ::unqualified-keys {:x 1 :y 2})   ; => true because required :x and optional :y present
(s/valid? ::unqualified-keys {:y 2})        ; => false because :x is required
(s/valid? ::qualified-keys {:x 1 :y 2})     ; => false because ::x is required
(s/valid? ::qualified-keys {::x 1})         ; => true

practicalli-johnny10:09:07

I did write a whole bunch of pages about spec, but still haven't got into the rhythm of regularly using them at work yet 😞 https://practical.li/clojure/clojure-spec/data/entity-maps.html#defining-entity-maps

popeye12:09:38

was looking into https://github.com/stuartsierra/component/blob/master/dev/examples.clj#L130 example of component, How this same as https://github.com/stuartsierra/component/blob/master/dev/examples.clj#L118 (defrecord ExampleSystem [config-options db scheduler app] I mean whenever I click on map->ExampleSystem it is pointing to (defrecord ExampleSystem

delaguardo12:09:31

https://clojure.org/reference/datatypes#_deftype_and_defrecord defrecord generates that function together with ->ExampleSystem variant

popeye12:09:48

map->Bar is defined that takes a map and initializes , what if we use vec->Bar , does that take vector argument?

delaguardo12:09:30

there are two functions: map->Bar and ->Bar there is no vec->Bar but you can call ->Bar with arglist

popeye12:09:55

can we call by Just Bar ?

Fredrik12:09:49

Yes, with (Bar. arg1 arg2 arg3)

👆 1
popeye12:09:12

. is necessary?

Fredrik12:09:36

It is syntax for (new Bar ...)

delaguardo12:09:13

(type Bar) ;; => java.lang.Class

Fredrik12:09:19

Behind the scenes, Bar is a Java class, and java classes are instantiated with new or the .

noisesmith15:09:11

use (->Bar ...) instead (Bar. ...) from clojure code

🙌 1
noisesmith16:09:23

I can imagine an alternate timeline where putting a class in a calling position would invoke the constructor - there's no alternate behavior / ambiguity since Class can't be extended to implement IFn

noisesmith16:09:05

I've also speculated Number in call position could have been implemented as * just like in math

noisesmith16:09:29

but that would lead to really weird error messages / bugs when you put number in call position accidentally

noisesmith16:09:16

or regex in call position doing re-matches

noisesmith16:09:52

actually if numbers multiplied when called, the common newb bug of ((+ x y)) would work as expected, for an unexpected reason: * with one arg is identity lol

Fredrik16:09:19

This all is possible in ClojureScript, since IFn is a ClojureScript protocols and hence extendable to every type. In Clojure the user can't extend Java interface to a type, if I understand correctly

noisesmith16:09:49

right - protocols can be extended, interfaces cannot, and IFn is an interface

noisesmith16:09:06

to be more concrete: you can only extend an interface at the time of class declaration, while protocols can be extended later

noisesmith16:09:39

so you could also fork the jvm itself to make Number implement IFn - absurd but technically possible

noisesmith16:09:30

@U024X3V2YN4 though I do have some suspicion that js engines might have special case code for numbers that could prevent our extension of numerics from working

Fredrik16:09:30

I think numbers work fine

(extend-type js/Number IFn (-invoke ([this op x] (op this x))))
#object[Function]
cljs.user=> (71 + 171)
242

noisesmith16:09:24

that's silly, at least making them implement multiply makes mathematical sense

noisesmith16:09:16

or more precisely: that's a syntactic change, I was suggesting a semantic change

noisesmith16:09:28

(syntax remains as is, numbers now mean multiply)

Fredrik16:09:38

This was en example posted by @U0CKDHF4L while ago, btw

noisesmith16:09:12

ahh OK - I'm allergic to infix sorry for the knee jerk

Fredrik16:09:55

No worries, I just added that because I forgot to give them credit! It's just a fun example, occuring in the discussion of why (nil) is syntax error, while (1) isn't, in Clojure.

noisesmith16:09:59

ClojureScript 1.10.758
(cmd)cljs.user=> (extend-type js/Number IFn (-invoke ([this & args] (apply * this args))))
WARNING: Protocol IFn implements method -invoke with variadic signature (&) at line 1 <cljs repl>
WARNING: Extending an existing JavaScript type - use a different symbol name instead of js/Number e.g number at line 1 <cljs repl>
#object[G__629]
(cmd)cljs.user=> (1)
#object[Number 1]
(cmd)cljs.user=> (3 7 2)
42
*fixed

octahedrion20:09:57

@U051SS2EU (71 + 171) is prefix when numbers are functions

noisesmith20:09:49

only if + is somehow a valid argument

noisesmith20:09:23

it's prefix emulating infix

octahedrion20:09:12

no, it's prefix. The number is a function which returns its value combined via the given operation with another number

octahedrion20:09:40

it is silly, as you say, but it's perfectly valid

Maravedis12:09:22

Is there a core function to test wheter a map is a subset of another ? Something like

(submap? {:a 1 :b 2} {:a 1 :b 2 :c 3}) ; => true

Alex Miller (Clojure team)12:09:13

No, but it's something I've written a lot of times for testing

Alex Miller (Clojure team)12:09:36

There are a lot of choices about what exactly is a sub map

Maravedis12:09:00

Guess I'll just write it then.

Maravedis12:09:28

Thanks for the indications.

Fredrik12:09:51

As @delaguardo mentioned, you can also compare part-in-both returned by diff against your potential submap. If they're equal, it's a submap.

🙌 1
Benjamin15:09:25

(some #{:foo :bar} (keys {:foo 10}))
(or (:foo thing) (:bar thing))
is there preferred way to check if either of some keys are present in a map?

dpsutton15:09:25

I’d use contains?

ghadi15:09:44

(some your-map [:k1 :k2 :k3])

noisesmith15:09:18

as long as false/nil are not in the val domain

1
dpsutton16:09:30

Also that requires that your keys are in vocable as a lookup. The contains? check contains neither of these two subtle buggy behavior for your purposes. Handles keys that aren’t in vocable and handles nil and false values in the map.

dpsutton16:09:04

Oh the map is invoked. I read it backwards

John Bradens17:09:27

Hi everyone, when I try to deploy my web app to heroku, I get the error

Error: Could not find or load main class
Any idea what I need to fix?

John Bradens17:09:15

When I first do

git push heroku main
I also get this error:
Error encountered performing task 'run' with profile(s): 'base,system,user,provided,dev,dev'

dgb2317:09:30

how does heroku build and invoke your application? which commands are used?

John Bradens17:09:27

I have a bin/build file that says this:

John Bradens17:09:29

#!/usr/bin/env bash
npm install
npx shadow-cljs release main
lein uberjar

noisesmith18:09:19

making an uberjar and "performing task 'run'" are mutually exclusive - if you do one the other isn't needed

John Bradens18:09:00

Thanks @U051SS2EU. I'm a total beginner. What commands do you suggest I have listed?

noisesmith18:09:23

pedantically, lein run (which is what produces that message you show elsewhere) is meant for local development, and not for running a program on a server

noisesmith18:09:37

but I know that heroku has its own tooling and might expect to use lein to run your app

noisesmith18:09:53

normally what I would do is produce a jar with lein uberjar , no need to AOT compile / gen-class my clj code, then run java -cp my-standalone.jar clojrue.main -m my.ns which uses the clojure.main class to load an run my code on startup

noisesmith18:09:13

but if you need to use lein run, there's no need to run the uberjar task

John Bradens18:09:35

Ok that makes sense. How do I fix the -main error I'm getting? In my project.clj file I have

:main ^:skip-aot kewl-app.core

noisesmith18:09:54

right, :skip-aot specifally requests that you don't produce a class

noisesmith18:09:20

so you need to tell the java process the right class to run - usually that would be clojure.main

John Bradens18:09:55

Ok, so I would change it to be

:main clojure.main 
or is there something else?

John Bradens18:09:40

And do I change my bin/build file to say

lein uberjar
java -cp my-standalone.jar clojrue.main -m my.ns

John Bradens18:09:30

For my project would I use kewl-app.core instead of my.ns? Thanks for helping @U051SS2EU

noisesmith18:09:34

right - and it would be target/something-standalone.jar based on the name of your project

noisesmith18:09:53

try running lein uberjar and see what files get created

noisesmith18:09:26

and yes, it would be the actual ns name instead of my.ns

noisesmith18:09:08

you can run all these things locally from a terminal to see what works

John Bradens18:09:26

I also have a Procfile that says this:

web: java $JVM_OPTS -cp target/kewl-app.jar \
     clojure.main -m kewl-app.core
Should I change any of that?

John Bradens18:09:41

Ok I ran lein uberjar in the terminal and got

Created /Users/user/kewl-app-deploy-2/target/uberjar/kewl-app-0.1.0-SNAPSHOT.jar
Created /Users/user/kewl-app-deploy-2/target/uberjar/kewl-app.jar

noisesmith18:09:23

weird - usually one has "standalone" in the name - try the kewl-app.jar one and see if it works

John Bradens18:09:43

Ok so I'm gonna try java -cp kewl-app.jar clojure.main -m kewl-app.core in the terminal

John Bradens18:09:07

Ok that's the cause of my error. I get

Error: Could not find or load main class clojure.main

noisesmith18:09:13

well it would be target/uberjar/kewl-app.jar unless you are in that directory

John Bradens18:09:37

Ohhhh I see thanks. That might be my issue. I'm going to try that now.

noisesmith18:09:10

you can open the jar in an editor (both emacs and vim support this for example) and see which resources are included - there should be class files for clojure in there

noisesmith18:09:20

as well as your source code and project resources

noisesmith18:09:36

or use the unzip or jar command on the cli to investigate the contents or unpack it if that's more comfortable

John Bradens18:09:36

Ok now I changed to target/uberjar/kewl-app.jar and now I get this error: ERROR kewl-app.core - Database configuration not found, :database-url environment variable must be set before running

John Bradens18:09:31

I did have a dev-config file with database-url. I deleted it because I thought Heroku had it's own database (I added on postgres with heroku). I just added the file back though and ran the lein uberjar command again and it still says there's no database url

noisesmith18:09:56

cool, so you found the right command line, you just didn't set the env var it expected - the stuff in project.clj that sets that is only applicable inside lein

noisesmith18:09:06

heroku should have its own setup for that

noisesmith18:09:28

the env var is provided by the shell, not the jar

John Bradens18:09:28

Ok awesome should I try heroku again?

noisesmith18:09:38

I think so yes

noisesmith18:09:42

a common thing is to separate the jar-building step from the running step, so that the app can be restarted (or started on another parallel instance) without having to rebuild the jar if your code hasn't changed

noisesmith18:09:59

but I don't know if/how this would work with heroku

Chase18:09:05

This might help cuz I know you have a big ole luminus template you are working off of: https://luminusweb.com/docs/deployment.html#heroku_deployment

❤️ 1
John Bradens18:09:17

Ok so I changed my procfile to have target/uberjar/kewl-app.jar instead of target/kewl-app.jar which was incorrect

John Bradens18:09:11

And just to confirm, in my project.clj I had :main ^:skip-aot kewl-app.core and I want to change this to :main clojure.main or should it be :main kewl-app.core ?

noisesmith18:09:56

you can keep the project.clj :main option the same as it was

noisesmith18:09:06

using clojure.main means that :skip-aot is fine

John Bradens18:09:19

Ok sounds good

John Bradens18:09:29

And then in my bin/build file I just want to have lein uberjar?

John Bradens18:09:57

I'm just double checking because I just tried running again and still got the no main class error

Chase18:09:00

don't forget to git add and commit before pushing to heroku so it picks up these changes

noisesmith18:09:23

is no main class a warning from lein or an error when running the jar?

noisesmith18:09:34

if it's a warning from lein you can ignore it

John Bradens18:09:14

@U9J50BY4C thanks I remember now since learning yesterday! Thanks for checking

John Bradens18:09:19

I am trying git push heroku main and then when it says it is built successfully, then I click on the app which says Application Error, and then I try heroku logs --tail and that is the only error I see. But I'll post the whole thing in case. There are some errors at the bottom I don't understand for example adn taht might be it

noisesmith18:09:00

it looks like it is treating \ which in a shell script is "continue this line" as a token, here the main class

noisesmith18:09:14

try taking out the \ and joining the lines

John Bradens18:09:17

Oh I see. I'll remove that and try again

noisesmith18:09:33

remember to join the next line too

John Bradens18:09:48

Ok now it's all on one line

John Bradens18:09:27

I'll try pushing to heroku again (after doing git init, git add ., git commit -m "fixing things") 🙂

Chase18:09:59

you don't need to use git init any more. That is just the first time you start a project.

John Bradens18:09:38

Ok progress!! Thanks for all the help. Now I can click on the app in Heroku and I just get a blank page, but the favicon and site title show up in the browser. I think this might be due to the port issue you mentioned yesterday @U9J50BY4C

John Bradens18:09:02

How do I link up the port correctly? And I also added on postgres, do you know if I have to do anything special for the database?

Chase18:09:59

DB I haven't figured out yet. But yeah, for port you need to just do something where instead of you saying {:port 8000} you say {:port (or (System/getenv "PORT") 8000)}

John Bradens18:09:16

Ok I made that change, and recompiling now

Chase18:09:20

If that doesn't work there is a chance that (System/getenv "PORT") returns a string so you need to convert to an integer first.

John Bradens19:09:46

Thanks, it didn't work so I'll try that

John Bradens19:09:20

I also get these warnings, so I think I might have up update the react dependencies to be 17 instead of 16? Do you think that might be affecting it?

John Bradens19:09:47

Do I use (Integer/parseInt (System/getenv "PORT")) to convert to an integer? Thanks again for all your help

Chase19:09:21

yep but change your default port (for when you are doing local development) to a string too or you get an error.

Chase19:09:39

(Integer/parseInt (or (System/getenv "PORT") "8000"))

Chase19:09:53

Those warnings are unrelated and have to do with Google closure compiler issues when trying to optimize your production build. Unfortunately when I tried to get help on #shadow-cljs I was told they weren't familiar with lein and/or the luminus template setup and were unable to help me. Part of the reason I started from scratch.

Chase19:09:59

Well at least that dead code elimination warning is about that. Not sure about the rest.

John Bradens19:09:01

Alright I added parseInt, and updated the dependencies it was warning about, and now I'm trying it again

John Bradens19:09:26

Ok that's interesting. How long did it take you to start from scratch? I want to build a basic social media type web app where people can post their own blog posts basically. I was following this book https://pragprog.com/titles/dswdcloj3/web-development-with-clojure-third-edition/ because it goes through how to add lots of features, but it's all based in luminus, so I'm not sure how I'd go about re-doing it all from scratch. But it might be worth it to try

Chase19:09:52

Yeah I have started with that book too and am using it alongside trying to build up from scratch. A lot of others recommend it as well. You will probably be fine with it. I just found whenever I built out my full stack app with it using the whole lein new luminus my-app +reitit +shadow-cljs +re-frame +... I just never really understood what I was looking at. Way too many moving parts for me to wrap my head around it.

Chase19:09:10

And it made it difficult to seek support because the luminus channel was dead and it was tough asking the right questions about things like the big project.clj file it setups up for you. I just never felt like I had a good grasp on my app.

Chase19:09:16

The good and bad of this amazing clojure slack community is I find I get totally stuck and would not be able to solve things without these folks. The offshoot is I try and gear some of my tech/library choices to those I've seen commonly discussed on here by helpful people so that I know I can get support if needed.

John Bradens19:09:51

That makes a lot of sense. Are there any books or resources you recommend for building from scratch? I think I'll look into it. Even if I still use the luminus template, I'd love to learn more

John Bradens19:09:06

Yes the slack community here is amazing. I'm so grateful for it.

John Bradens19:09:54

Ok recompiled and still nothing shows up 😕 any ideas what it might be? I can try asking again in the main channel too

Chase19:09:34

What do the heroku logs say is the issue?

Chase19:09:05

This channel has been great for down to earth explanations for some of the things we are looking to do: https://www.youtube.com/watch?v=yVb8PS6a4Mk&amp;list=PLqunUpREWrwKdi3DEkTnIia54JjnWk8JB&amp;index=7

Chase19:09:39

Here he happens to be creating an app where users can post articles, which could be perfect for you.

Chase19:09:35

I'm still using that web dev book but I'm starting from scratch like they do after the 2nd chapter or whatever instead of using the huge template starter with all the tech I eventually want

Chase19:09:13

So anyways, if the heroku logs are telling you that there was a "timeout" situation or something when trying to connect then you are still having the port issues.

Chase19:09:00

You could push your current repo to github again git push origin main and I could take a look maybe.

John Bradens19:09:13

Here is my logs from heroku. Can you help me decipher it?

John Bradens19:09:58

I LOVE that youtube channel. I haven't seen those videos because I felt intimidated by http-fx and all the new stuff but I should probably work through them

John Bradens19:09:32

I tried for a while to correct my react dependencies but that didn't fix anything

John Bradens19:09:55

I'll push to git again and post here I would really, really appreciate if you have time to take a look at it

Chase19:09:46

Do you see anything if you go to one of these routes like /api?

Chase19:09:23

Where in the code are you specifying what happens with just the / index route?

John Bradens19:09:09

I have a routes.app.cljc file : (almost exactly like the guestbook examples from the book)

(ns 
  (:require
   [spec-tools.data-spec :as ds]
   #?@(:clj [[kewl-app.layout :as layout]
             [kewl-app.middleware :as middleware]]
       :cljs [[kewl-app.views.home :as home]
              [kewl-app.views.about :as about]
              [kewl-app.views.profile :as profile]
              [kewl-app.views.author :as author]
              [kewl-app.views.upload :as upload]
              [ :as post]
          ])))
;;...
;
#?(:clj
   (defn home-page [request]
     (layout/render
      request
      "home.html")))


;
(defn app-routes []
  [""
   #?(:clj {:middleware [middleware/wrap-csrf]
            :get home-page})
   ;
   ;; require [spec-tools.data-spec :as ds]

   ["/"
    (merge
     {:name ::home}
     #?(:cljs
        {:parameters {:query {(ds/opt :post) pos-int?}}
         :controllers home/home-controllers
         :view #'home/home}))]

Chase19:09:56

where are you setting the port?

Chase19:09:32

Unfortunately, I think you have surpassed my abilities to help at this point. And we are probably way too deep to have others following this thread so you may need to start a new one. haha. sorry

John Bradens20:09:07

No worries! Thanks so much for all your help. I couldn't have gotten this far without you.

Chase20:09:11

And all this works when you are developing locally on your own machine?

John Bradens20:09:34

Yes it does! Although with all the changes I should probably double check that it still runs on localhost

John Bradens20:09:54

I just realized I had a typo in my Database_url setting so I'm going to fix it and try running again

Chase20:09:51

You can see a 404 error in the console when looking at the main page of your app too. It is not finding your app.js file created by shadow-cljs I don't think.

John Bradens20:09:51

Ok I must have messed something up when I starting making edits to try and deploy on heroku...

John Bradens20:09:00

Thanks for letting me know

John Bradens20:09:30

I saved a version of the project right before trying to deploy. I might go back to that version of my project, make sure it works locally, follow all the steps I learned here, and see where that gets me.

Chase20:09:41

Sounds good. I had a single typo that prevented anything showing up on my own site myself but your repo is too big for me to see where everything is routing and whatnot

John Bradens20:09:58

When i have my dev-config.edn file the way it was previously, I can get the app working. When I replace :port 3000 with :port (Integer/parseInt (or (System/getenv "PORT") "3000")) I get

Syntax error (ClassCastException) compiling at (/private/var/folders/9q/1d7v8kjx3y3d9ntysj9js76c0000gn/T/form-init2785940755153321540.clj:1:125).
class clojure.lang.PersistentList cannot be cast to class java.lang.Number (clojure.lang.PersistentList is in unnamed module of loader 'app'; java.lang.Number is in module java.base of loader 'bootstrap')

John Bradens20:09:55

*I can get the app working locally, not heroku lol

John Bradens20:09:52

I have to go to a few zoom meetings now but I will tinker a little more and then ask the slack channel about how my dev-config.edn should be set up for heroku deployment. I think the way I have my database is also wrong so I'll have to ask about that regardless. Thanks again SO MUCH for all your help. I hope you have a great rest of your day @U9J50BY4C

Chase20:09:14

I wonder if on your own local system you already have something set to PORT. What does (System/getenv "PORT") give you at the repl?

noisesmith20:09:58

that error from config.edn is because the list (Integer/parseInt (or (System/getenv "PORT") "3000")) isn't evaluated, just read

John Bradens20:09:53

@U9J50BY4C I get zsh: no such file or directory: System/getenv

John Bradens20:09:21

@U051SS2EU thanks! How do I make it evaluate? I just tried doall but I got errors again

noisesmith20:09:22

the edn file will not be evaluated

John Bradens20:09:04

Oh I see. Do I need to add any new file to specify post & database_url or does heroku take care of that automatically?

Chase22:09:32

oh ok. hmmm. Somewhere in your actual clojure code you are probably reaching in to that config file for the port. That is where you would put in the whole (Integer...) thing.

Chase22:09:58

I think heroku might default to port 8080 so you could just try that but I wouldn't rely on that at all. But just something desperate I would try to see my app deployed. haha

Chase22:09:01

Another thing I would try is add $PORT at the end of your Procfile command but I suspect your own code might override that

John Bradens23:09:32

Wow so I tried again from a previous version I had, and followed all the same steps only changed what worked to change, ie adding the bin/build file, editing the procfile to remove the / and have it all on one line, and I just commented out the whole dev-config.edn that had the ports. Now the app shows up!

John Bradens23:09:16

I don't think I have the database connected or working, but I will look at the link you sent https://folcon.github.io/post/2020-04-12-Fulcro-on-Heroku/ because there is a section on postgres there

Chase23:09:11

alright! That's a fun feeling huh

John Bradens23:09:55

Feels amazing!

🎉 1
noisesmith18:09:02

that message about a main class means you didn't AOT compile / gen-class the ns with -main in it, or didn't declare one

noisesmith18:09:33

one workaround is to specify clojure.main as your main class (comes compiled for you with clojure.jar) and then provide your ns as a startup arg to clojure.main

vlad_poh18:09:18

Any good guidelines on wrapping a rest api as a clojure library?

vlad_poh18:09:49

Any good examples to look at?

hiredman18:09:11

basically a single "invoke" function that you pass descriptions of the operation you want to peform

👍 1
hiredman18:09:35

I recently wrote a little client for the google androidpublisher api at work, and call it looks something like

(adp/invoke!!
 androidpublisher
 {:op :purchases.subscriptions/defer
  :packageName app-id
  :subscriptionId in-app-product-id
  :token token
  :request {:deferralInfo
            {:expectedExpiryTimeMillis (str (:expiryTimeMillis subscription))
             :desiredExpiryTimeMillis  (add-days (Long/parseLong (:expiryTimeMillis subscription)) 360)}}})))

hiredman18:09:32

the code that invoke!! eventually calls uses the json document google publishes describing the api to figure out urls, methods, etc

Jason19:09:10

This is such a beginner question but if you had a vector of strings how would you go about removing the last character from the last array? So this:

["this" "is" "the" "string"]
becomes this:
["this" "is" "the" "strin"]

R.A. Porter19:09:46

There are a lot of ways to do that. Here's one (it's pretty ugly):

(let [l ["this" "is" "the" "string"]]
    (assoc l (dec (count l)) (apply str (butlast (last l)))))

R.A. Porter19:09:24

Or...

(let [l ["this" "is" "the" "string"]]
    (conj (vec (butlast l)) (apply str (butlast (last l)))))

☝️ 1
Apple19:09:29

(update ["this" "is" "the" "string"] 3 #(subs % 0 4))

Apple19:09:18

(let [x ["this" "is" "the" "string"]]
  (update x (dec (count x)) #(subs % 0 (dec (count %)))))

R.A. Porter19:09:12

(let [[l & ?rest] (reverse ["this" "is" "the" "string"])]
    (conj (vec (reverse ?rest)) (apply str (butlast l))))

R.A. Porter19:09:03

Our point, of course, being that there are a LOT of ways. Some more or less efficient, clear to read, idiomatic, etc.

sheluchin19:09:21

(let [x ["this" "is" "the" "string"]
      y (last x)
      z (clojure.string/join (butlast y))
      res (conj (vec (butlast x)) z)]
  res)

randomm char19:09:53

(def a ["this" "is" "the" "string"]) (conj (pop a)(subs (last a) 0 (+(count a) 1)))

sheluchin19:09:21

Is there a Clojure golf webapp with users somewhere out there?

randomm char19:09:57

Only thing I know is https://codegolf.stackexchange.com/ its not clojure specific

Jason19:09:01

Oh wow, wasn’t expecting to have such a range of answers

Jason19:09:38

Judging from your answers there isn’t a right way either?

sheluchin19:09:11

Yeah, not really a right way. There's probably some solution that incorporates the threading macro to make things a bit more legible, but it's a simple enough problem that any one of the possible solutions is good enough in most cases.

vlad_poh19:09:56

Did someone say code golf? (defn fx [c] (conj (pop c) (apply str (butlast (last c))))) (fx ["this" "is" "the" "string"]) => ["this" "is" "the" "strin"]

Jason20:09:29

Sometimes clojure just feels so much harder than other languages 😅

Young-il Choo20:09:43

Yes, Clojure is harder for some tasks than other languages like Python where you just side-effect the last element of the array. The reason is that without side effects, we have to pick out the last part of the vector, create a new value (without the last character), then create a new vector that has that as the last element. See @UPWHQK562’s code. Why do this extra work? (Exercise for the reader ?)

Jason20:09:35

Because we like pain 😂

seancorfield22:09:26

If you start with a vector, peek and pop are the "fast" ways to interact with it. last is linear, peek is "much more efficient than last" (per the docstring).

seancorfield22:09:37

dev=> (let [l ["this" "is" "a" "string"]
 #_=>       w (peek l)]
 #_=>   (conj (pop l) (subs w 0 (dec (count w)))))
["this" "is" "a" "strin"]

schmee22:09:02

with Specter:

user=> (setval [LAST LAST] NONE ["this" "is" "the" "string"])
["this" "is" "a" "strin"]
https://github.com/redplanetlabs/specter/

schmee22:09:18

reads way better than any of the clojure.core solutions IMO

seancorfield22:09:48

That's debatable. I find Specter's "DSL" style to be impenetrable for the most part. And I think it's a poor choice for beginners until they've got a good, solid understanding of the core data structures and their O(1) vs O(n) operations.

Jason08:09:18

So I’ve been thinking about this some more and wondering if anyone has any abstractions for these kind of problems. I was thinking of making a function called something like apply-only and it only performs the transformation if it passes some test or maybe if it’s in a range passed in. Has anyone done anything like this already?

seancorfield16:09:29

Sounds like cond->

schmee18:09:25

@U028TA3H3PA take a look at Specter that I posted above, it is precisely “abstractions for these kind of problems”

Jason07:09:37

Okay great thanks, I’ll take a look at these

John Bradens19:09:16

If I see a dependency that has "^16.0.0" what does that ^ symbol mean?

luizmineo19:09:16

It means any version in the range 16.X.X. See https://docs.npmjs.com/about-semantic-versioning

John Bradens19:09:48

Cool thank you

hiredman19:09:04

That is for npm and JavaScript packages, maven style dependencies (common in clojure) don't do that

John Bradens19:09:09

Ok thanks, good to know!

randomm char19:09:36

Not sure how much overlap there is between slack/clojure and reddit/clojure I ended posting my code for review on reddit, I got some feedback. This is basically my first program time doing this , posting my code for feedback. Before this I basically just opened a repl did some really short stuff. https://github.com/rng-ftw/basic-paint its a really basic paint style program nothing fancy save file to test.txt where ever file is run from loads from same location does nothing if the file does not exists any feedback would be appreciated.

phronmophobic20:09:48

you can also try posting in #code-reviews

phronmophobic20:09:45

some thoughts: • in update state, it looks like the arg, state, is a map, but it's used as a function. There are times when using maps as functions is useful, but if you're just using it as a map, I would prefer (:button-state state) over (state :button-state)(doall (map ..)) can be replace with (run! ...) • I'm a little confused by the cond-> usage. I would probably either use cond if only one branch is to be chosen or just have a bunch of when statements. • some of the lines are really long 😛 • for the functions that handle lots of cases using cond, I might consider breaking them up and using something like multi methods or reduce to compose them.

randomm char00:09:32

Thanks for looking at the code, appreciate it. Guess I really dont understand the difference between (:button-state state) and `(state :button-state)` They functionally do the same thing ?? dorun doall and run! all basically seem to do the same thing havent found anything that really differentiates them Yeah the cond-> initially I though was going to have to modify several different states at once but if I pull out quil I might be able to do it without cond->

phronmophobic06:09:35

> Guess I really dont understand the difference between `(:button-state state)` and `(state :button-state)` Since state is a map, the result is the same. However, programming is about communicating with future readers of the code as much as it is about getting the right result. The two different versions communicate different intents: • (:button-state state): look up the key :button-state in the associative data structure, state(state :button-state): call the function state with :button-state as the first argument. The difference between doall+`map` vs run! is similar. • (doall (map ..)): create a lazy sequence using map and force execution now. Additionally, doall will cause the full sequence to reside in memory as opposed to dorun(run! ...): execute a function for each item in a collection for side effects. Generally, it's easier to give advice about stylistic stuff so that's what you'll tend to get in code reviews. The main design idea I would consider is that update-state combines many different operations into one place. I would try to split up all the operations into their own separate pieces that can be used/tested/debugged in isolation.

randomm char18:09:02

Thanks for the reply. yeah update-state seems to of become a catch all. The basic idea was the capture state change in one location...

César Augusto22:09:39

Hi everyone! I am trying to replace a string using https://clojuredocs.org/clojure.string/replace but my match is not a literal string it is a value, how can I do that? for example. Instead of:

(clojure.string/replace "The color is red" #"red" "blue")
It is:
(def color <value-recupered-from-http-param>) ;; -> "red"
(clojure.string/replace "The color is red" color "blue")
🧵

seancorfield22:09:14

Look at re-pattern

👍 1
César Augusto22:09:59

(def color <value-recupered-from-http-param>) ;; -> "red"
(clojure.string/replace "The color is red" (re-pattern color) "blue")

noisesmith18:09:24

you don't need an re:

user=> (clojure.string/replace "the red color" "red" "blue")
"the blue color"

👍 1
noisesmith18:09:24

> match/replacement can be: > > string / string > char / char > pattern / (string or function of match).

seancorfield19:09:35

True. But since the OP had a #".." regex, I assumed they wanted to treat the http param as a regex 🙂

👍 1
piyer23:09:04

Is there a clj or java lib that can do exif removal from a image?