beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
st3fan 2020-12-04T02:49:02.435400Z

Is there a way to repeatedly call a function, feeding it its own output?

st3fan 2020-12-04T02:49:43.435900Z

(foo (foo (foo (foo 42))))

dpsutton 2020-12-04T02:50:04.436400Z

Check out iterate. (Iterate foo 43)

st3fan 2020-12-04T02:51:26.437200Z

oh so i would grab (last (take 1000 (iterate foo 42))

st3fan 2020-12-04T02:51:37.437400Z

Maybe that is nth

๐Ÿ‘ 1
st3fan 2020-12-04T03:14:59.439800Z

Working on an old Advent of Code puzzle .. so odd .. this works (take 2 (iterate simulate-motion system))

st3fan 2020-12-04T03:15:18.440200Z

But when I hit 3 .. (take 3 (iterate simulate-motion system))) .. class clojure.lang.LazySeq cannot be cast to class

st3fan 2020-12-04T03:16:35.440500Z

Hm again I am bitten by lazy seqs

st3fan 2020-12-04T03:17:21.440800Z

(defn simulate-motion [system]
  (->> system
       (system-apply-gravity)
       (map planet-apply-velocity)))

st3fan 2020-12-04T03:17:38.441200Z

The last map turns my system (a vector) into a lazy seq

seancorfield 2020-12-04T03:20:46.441500Z

@st3fan Use mapv ?

st3fan 2020-12-04T03:22:11.441700Z

wonderful!

st3fan 2020-12-04T03:28:54.442200Z

I should really just read clojure.core

โž• 3
st3fan 2020-12-04T16:06:22.462400Z

LOL

phronmophobic 2020-12-04T03:32:09.443200Z

clojure.core is just really interesting generally to see the language build itself

Sam Stowers 2020-12-04T03:45:05.444400Z

Hi! Please let me know if this is the wrong place, but I'm learning Clojure and have a simple problem I'm mystified by

Sam Stowers 2020-12-04T03:45:50.445200Z

Clojure is telling me that two (what appear to be identical) strings are not equal, but only in the context of this one function.

Sam Stowers 2020-12-04T03:46:38.445700Z

(defn any-chars-match
  "Checks if any chars in a string match the single char in the second string. If any do, return true. Otherwise return false."
  [comparisonChars checkChar]
  (reduce (fn [passedVal compareChar]
            (if (= compareChar checkChar) ;; This always evaluates false
              (reduced true)
              false))
          false
          (seq comparisonChars)))

2020-12-04T17:57:56.472400Z

another thing that would have helped is prn instead of println -

(ins)user=> (println ["k" \k])
[k k]
nil
(cmd)user=> (prn ["k" \k])
["k" \k]
nil

โž• 1
2020-12-04T17:58:52.472600Z

(there's also pr-str for getting the pr behavior inside arbitrary output from println / format)

Sam Stowers 2020-12-04T20:12:04.001100Z

How are you all so helpful

Sam Stowers 2020-12-04T20:15:19.001300Z

This is my first interaction w/the Clojure community - posted a question and multiple helpful replies in minutes. Never really seen this before. ๐Ÿ™‚

2020-12-04T20:16:33.001500Z

haha, we try

๐Ÿ™Œ 1
Sam Stowers 2020-12-04T03:47:22.446200Z

Tried logging each value and the comparison, but that still looks identical

Sam Stowers 2020-12-04T03:48:09.447Z

Could someone tell me what I'm missing? Read up on the = function, tried using identical?, still no idea

seancorfield 2020-12-04T03:49:52.447100Z

@st3fan You might find this (early access) book valuable: https://www.manning.com/books/clojure-the-essential-reference

phronmophobic 2020-12-04T03:52:07.449700Z

Iโ€™m away from keyboard but i think the issue is that compareChar is a char and checkChar is a string in your example. does (checkChars โ€œkkโ€ \k) work?

seancorfield 2020-12-04T03:52:53.450Z

That was what I was about to say: you're comparing characters to a string.

seancorfield 2020-12-04T03:54:03.450200Z

When you do seq on a string, you get a sequence of characters, so (seq "kk") is (\k \k) and then you're comparing \k against "k" which are not equal @sam694

Sam Stowers 2020-12-04T03:54:33.450400Z

Ah, knew I was missing something dumb - should've checked the types

Sam Stowers 2020-12-04T03:54:49.450600Z

Thanks for the quick reply @smith.adriane @seancorfield, really appreciate it

dpsutton 2020-12-04T04:32:47.450800Z

and remember to play around in your repl (seq "kk") probably would have shed some light

dpsutton 2020-12-04T04:33:19.451Z

to mimic what your (seq comparisonChars) is doing. ironically, the answer is in your variable name ๐Ÿ™‚ comparison`Chars`

Sam Stowers 2020-12-04T06:28:27.453300Z

I did that very thing in the REPL, but I didnt put 2 and 2 together that chars were a different data type than strings. Learned today to pay more attention to such things lol

Sam Stowers 2020-12-04T06:29:27.454Z

Coming from JavaScript, which doesn't use the distinction

dpsutton 2020-12-04T06:33:32.454200Z

yeah. clojurescript is the same way due to that.

dpsutton 2020-12-04T06:33:40.454400Z

its a surprise for sure

phronmophobic 2020-12-04T06:34:06.454600Z

part of the distinction is driven by using the built in Java types (which dramatically helps performance). not sure if the design would be the same if reusing the built in java string and char types wasn't as beneficial

2020-12-04T12:26:49.458700Z

Trying to make a websocket app using http-kit, Sente and Reitit. Something is broken and don't know what, browser says it fails to connect, gets some 406's back from the websocket requests. The code is still minimal and nearly identical to working Sente examples except I'm not using Compojure, so I'm stumped on what is the problem... The relevant files are router.clj and websocket.clj at https://gitlab.com/salohonka/tic-tac-toe/-/tree/master/src/clj/tic_tac_toe. I've tried to substitute http-kit for Jetty9 and Reitit for Compojure, but no luck :thinking_face:

C-Squirrel 2020-12-04T13:41:54.460400Z

Hi. I have a newbie question around plumatic.schema. Given this simple schema, how would I indicate either foo or bar must be provided? (one or the other must be there, but not both)

[{
:id s/Int
:name s/Str
:foo s/Str
:bar s/Int
}]

sova-soars-the-sora 2020-12-04T15:55:58.461400Z

Oo a websocket app, nice! Tell me more about how you are hosting your server? nginx? apache? I think websockets need a special outer layer, too.

sova-soars-the-sora 2020-12-04T15:57:50.461600Z

Usually I use all of Sente if working on a real-time app, and hack with a machete. But also be mindful that it might need a reverse-proxy (apache) or something similar (for nginx) ... hope that helps. if not, i am confident we can get down to the bottom of it.

st3fan 2020-12-04T16:05:49.462300Z

So here you have it .. I'm working on some Python code for work and I just C-c C-c to try out a code snippet

sova-soars-the-sora 2020-12-04T16:08:10.462700Z

PythonREPL?

2020-12-04T16:20:54.462800Z

Not using any dedicated webserver, it's a hobby project. Using Sente for both back and front, but I don't think the problem lies with Sente itself, as using just http-kit and it's builtin websocket handler also returns 406's

2020-12-04T16:21:45.463Z

I will try later if it's a configuration/computer problem by making an empty lein project, adding only http-kit and seeing if that will return 406's as well. If it does, I'll start something without websockets

sova-soars-the-sora 2020-12-04T16:46:42.463500Z

Oh you're running it locally?

sova-soars-the-sora 2020-12-04T16:49:20.463700Z

Hmmmmmm. curl from the command-line can be helpful to see what's coming back, too.

2020-12-04T16:58:37.463900Z

I've tried a websocket tester, not curl in particular, but it does connect successfully to other websockets so i'm sure it's the server. First get/handshake returns 101, but then any request after 406's. If you are interested, clone and run the project

2020-12-04T17:31:09.464700Z

How do I take something like this and turn it into a map: ((foo bar) (baz qux)) -> {:foo "bar", :baz "qux"}

dpsutton 2020-12-04T17:32:39.465Z

is (foo bar) a sequence of symbols?

dgb23 2020-12-04T17:32:51.465300Z

generally it would be into

2020-12-04T17:33:37.465900Z

No they are strings. I am trying (map #(into {} %)) but I get:

java.lang.Character cannot be cast to java.util.Map$Entry

alexmiller 2020-12-04T17:34:23.466300Z

entries need to either be Map$Entry or 2-element vectors

dpsutton 2020-12-04T17:34:34.466900Z

(into {} (map (fn [[k v]] [(keyword k) v])) '(("foo" "bar") ("baz" "qux")))

alexmiller 2020-12-04T17:34:35.467Z

lists don't allow indexed access

Lars Nilsson 2020-12-04T17:35:29.467800Z

(zipmap (map keyword (map first coll)) (map second coll)) maybe?

2020-12-04T17:37:09.468800Z

basically im trying to convert a string like โ€œfoo:bar baz:quxโ€ into a map {:foo "bar", :baz, "qux"} . Iโ€™m using re-seq but maybe thereโ€™s an easier way?

dpsutton 2020-12-04T17:39:53.469400Z

that seems fine. can also do a straightforward clojure.string/split

(into {}
      (map (fn [s] (let [[k v] (clojure.string/split s #":")]
                     [(keyword k) v])))
      (clojure.string/split "foo:bar baz:qux" #" "))

2020-12-04T17:43:36.469700Z

oh the destructing in that let binding is slick

dpsutton 2020-12-04T17:46:02.470400Z

and just to make it clear for this channel, i used clojure.string/split so it was clear what function i was using but you should require that in your namespace and alias it.

alexmiller 2020-12-04T17:51:44.471200Z

Any time you are using first/second/nth that should be a clue to use destructuring

2020-12-04T17:55:38.472300Z

(->> (input "resources/day4.txt" #"\n\n")
  (map #(clojure.string/replace % "\n" " "))
  (map #(clojure.string/split % #" "))
  (map #(let [[k v] (clojure.string/split % #":")]
          [(keyword k) v]))
  (map #(into {} %)))
Am I missing something here? clojure.lang.PersistentVector cannot be cast to java.lang.CharSequence

2020-12-04T18:00:29.473200Z

you are calling a string operation on a vector

2020-12-04T18:00:47.473900Z

if you look at the stack trace it should show which step is actually doing so

dpsutton 2020-12-04T18:01:17.474400Z

your split will return a vector and then you're calling split on that

dpsutton 2020-12-04T18:02:06.475300Z

always helpful to do all of the mapped functions on a single thing and make sure it works and then map them over the whole collection. and a sequence of maps like this you could just combine them into one function

st3fan 2020-12-04T18:02:49.476900Z

I did a very different solution for parsing the input .. check the Answers thread on #adventofcode ๐Ÿ™‚

dpsutton 2020-12-04T18:03:03.477400Z

ie, (->> col (map f) (map g)) could just be (map (comp g f) coll). then its very easy to see that the composition works in the single case and therefore necessarily works on the collection

dpsutton 2020-12-04T18:03:39.478100Z

(and here don't literally use comp but make a single function which does what you want to "one thing")

2020-12-04T18:05:34.479300Z

yeah - that stack of #() blocks is much less clear than a single function doing each of those steps would be

2020-12-04T18:06:31.480800Z

in fact, you probably want (->> (input ...) (map (fn [el] (-> el (string/replace ...) (string/split ...) ...))) you can stil use an arrow, but do it in the more useful place

dpsutton 2020-12-04T18:07:26.482Z

and stylistically, make a function that takes the input file and returns a sequence of the lines (doing all the #"\n\n" stuff and splitting. then a single function that processes a single line. and then (map process-line (get-input "resources/day4.txt")). makes it very easy to call process-line on a literal "foo:bar baz:quux" to check yourself

2020-12-04T18:13:09.482200Z

Created an empty project, added http-kit as a dependency and wrote

(defn handler [req]
  (hk/as-channel req {:on-open (fn [_] (println "connection"))
                      :on-receive (fn [_ msg] (println msg))}))

(defn -main [& _args]
  (hk/run-server handler {:port 3000}))
which did work, so the problem is project specific. Since the app is going to be very simple, I might just drop Sente on the backend and use http-kits own websocket handling

dpsutton 2020-12-04T18:27:36.482900Z

an example here if you wanted to see

mathpunk 2020-12-04T18:29:50.484700Z

What's a nice function for taking a seq as input and returning all (unordered) pairs where no element is paired with itself?

mathpunk 2020-12-04T18:31:20.485Z

I thought about math.combinatorics, then thought I'd write a nested for, then noticed I'd get more pairs than i wanted

2020-12-04T18:32:28.485200Z

(into #{} (for [a lst b lst :when (not= a b)] #{a b}))

mathpunk 2020-12-04T18:32:53.485400Z

:male-cook::skin-tone-2: ๐Ÿ’‹

mathpunk 2020-12-04T18:32:58.485600Z

thank you

2020-12-04T18:33:02.485800Z

(ins)user=> (def lst (range 10))
#'user/lst
(ins)user=> (into #{} (for [a lst b lst :when (not= a b)] #{a b}))
#{#{6 3} #{7 1} #{4 3} #{0 1} #{7 5} #{7 6} #{3 5} #{0 4} #{0 9} #{0 7} #{5 8} #{7 3} #{4 8} #{0 3} #{2 8} #{9 5} #{9 8} #{6 5} #{0 6} #{1 4} #{1 8} #{6 8} #{7 4} #{6 9} #{4 6} #{6 2} #{7 2} #{3 8} #{1 6} #{1 5} #{4 2} #{7 9} #{1 3} #{1 2} #{0 2} #{4 9} #{3 9} #{1 9} #{2 5} #{4 5} #{7 8} #{3 2} #{2 9} #{0 8} #{0 5}}

2020-12-04T18:33:58.486Z

rule 0 of clojure: use the data type that gets the closest to the behavior you need

dpsutton 2020-12-04T18:34:34.486200Z

that will exclude a bit too much if the source collection is not distinct

dpsutton 2020-12-04T18:35:36.486400Z

(let [coll [:a :b :c :a]]
  (for [i (range (count coll))
        j (range (count coll))
        :when (not= i j)]
    (into #{} [(nth coll i) (nth coll j)])))

dpsutton 2020-12-04T18:36:02.486600Z

not sure if that's important for you. some of these sets would be single element sets

2020-12-04T18:38:49.486800Z

I took "no element is paired with itself" to mean equality, not input position

2020-12-04T18:40:40.487Z

based on "unordered pairs"

mathpunk 2020-12-04T18:43:41.487200Z

the source collection happens to be distinct

mathpunk 2020-12-04T18:44:15.487400Z

and yeah the operation i'm feeding this data to is commutative

yiorgos 2020-12-04T19:38:19.489200Z

Hello, when I do (Integer/parseInt "1") I get back 1 but when I do (map Integer/parseInt ["1" "1"]) I am getting the following error Unable to find static field: parseInt in class java.lang.Integer

alexmiller 2020-12-04T19:39:33.489500Z

Integer/parseInt is not a function but a java static method

2020-12-04T19:39:42.489700Z

(map #(Integer/parseInt %) ["1" "1"])

alexmiller 2020-12-04T19:39:45.490Z

wrap it in an anonymous function

alexmiller 2020-12-04T19:39:53.490400Z

(map #(Integer/parseInt %) ["1" "1"])

yiorgos 2020-12-04T19:40:03.490600Z

Oh I see, thank you very much guys!!!

yiorgos 2020-12-04T19:40:17.491Z

I need to write that down in my Clojure notes ๐Ÿ˜„

2020-12-04T19:41:03.491800Z

There's also a function I think in core (can't remember which) to convert a method to a function, but just wrapping it in an anonymous function is more common and convenient most of the time.

๐Ÿ‘ 1
alexmiller 2020-12-04T19:44:47.492700Z

memfn is that but generally it's not worth using because it introduces reflection

โœ”๏ธ 1
Lars Nilsson 2020-12-04T19:47:18.493700Z

Could use (map clojure.edn/read-string ["1" "2"])

2020-12-04T19:49:44.493800Z

Hum... so it does something funkier then just doing (fn ~name [& args#] (. method ~@args#))

yiorgos 2020-12-04T19:54:15.494600Z

is there any difference between using edn reader and a java static method?

seancorfield 2020-12-04T19:59:06.495700Z

edn/read-string will read pretty much Clojure form -- hash maps, vectors, as well as numbers, strings etc. Generally, your Java static methods are going to parse just one specific thing.

2020-12-04T20:00:27.496800Z

It depends on your use case. They parse thing differently. If you want an Int back, better use Integer/PartseInt. If you are okay getting any type of number back (or possibly even other types like getting a string, a vector, erc. Then you can use edn read-string. Where as ParseInt will throw an error if the thing you have can't be parsed as an Integer.

alexmiller 2020-12-04T20:05:32.497200Z

well, read-string will never return an Integer, only Long :)

๐Ÿ˜ฎ 1
alexmiller 2020-12-04T20:06:06.497700Z

for this particular case, I would use Integer/parseInt (or Long/parseLong)

alexmiller 2020-12-04T20:07:11.498800Z

well it's effectively same

yiorgos 2020-12-04T20:07:19.499300Z

Thank you all! Very much appreciated the extra info ๐Ÿ‘

alexmiller 2020-12-04T20:07:28.499500Z

it's ensuring that type hints on memfn will transfer

phronmophobic 2020-12-04T20:08:20.000400Z

(clojure.edn/read-string {:readers {'an-int int}} "#an-int 42")
๐Ÿ˜›

alexmiller 2020-12-04T20:09:19.000600Z

....for some definition of "never" :)

๐Ÿ˜ 1
๐Ÿ˜‚ 1
Lars Nilsson 2020-12-04T20:10:12.000900Z

Or BigInt if the number is big...?

2020-12-04T20:21:36.001900Z

Oh, so doing that somehow limits the ability of the compiler to not use reflection? Versus wrapping it in an anonymous function?

sova-soars-the-sora 2020-12-04T20:35:14.002300Z

Yeah why not. Chime in again if you run into any issues ^.^

alexmiller 2020-12-04T20:37:15.002600Z

type hints on memfn will work (because the impl ensures they are transferred into the interop call)

alexmiller 2020-12-04T20:38:34.002800Z

there's nothing magical here wrt the compiler or reflection

2020-12-04T20:56:05.004100Z

I can conditionally add something to a vector based on a condition, with when.

(def whatev true)
[1 2 3 (when whatev 4)]
Is it possible (similarly) to conditionally add a map entry using when? This doesnโ€™t work (fails with Map literal must contain an even number of forms):
{:a 1 :b 2 (when whatev (:c 3))}

dpsutton 2020-12-04T20:56:47.004600Z

that unconditionally adds either nil or 4

dpsutton 2020-12-04T20:57:39.005800Z

(cond-> [ 1 2 3] whatever (conj 4)) and (cond-> {:a 1 :b 2} whatever (assoc :c 3)) are the standard ways to do this

๐Ÿ‘ 1
2020-12-04T20:57:51.006Z

ah, that makes more sense. thank you

uosl 2020-12-05T13:33:55.012800Z

(merge {:a 1 :b 2} (when whatever {:c 3})) and (into [1 2] (when whatever 3)) are also alternative ways to do this.

2020-12-04T21:29:43.006500Z

Hum, I guess I'm just confused then, say Class/foo is overloaded and I do:

(map #(Class/foo %) coll)

;; or

(map (memfn Class/foo) coll)
Won't they both use reflection?

2020-12-04T21:31:00.006700Z

Oh, I guess memfn doesn't even work for static

2020-12-04T21:32:02.006900Z

But ok, ignoring that, is there any difference in terms of reflection between:

(map (memfn toUpperCase) ["a" "b"])
("A" "B")
;; and
(map #(.toUpperCase %) ["a" "b"])
("A" "B")

st3fan 2020-12-04T22:13:10.008100Z

Is there a partition-by that can throw out the โ€œmarkersโ€ ?

st3fan 2020-12-04T22:13:56.009400Z

For example I partition on nil but donโ€™t want the nils. I use take-nth to skip them now. Would be nice to leave that out.

st3fan 2020-12-04T22:15:01.010Z

Maybe the answer is: donโ€™t be afraid to compose pipelines

โž• 2