Fork me on GitHub
#beginners
<
2022-11-28
>
zach00:11:58

Hello! I have a question about clojure style: Let’s say i have a seq made up of similarly structured seq-pairs, e.g:

[
[["a""b""c"][1 2 3]]
[["foo""bar""baz"][4 5 6]]
]
And I want to map through this seq, but apply a different map function for (first seq-pair) and (second seq-pair) e.g. in the example above, i want to uppercase all the strings for the first seq and increment the numbers for the second, getting:
[
[["A""B""C"][2 3 4]]
[["FOO""BAR""BAZ"][5 6 7]]
]
is there a built-in function to do this, or an idiomiatic way to do this?

zach00:11:48

At the moment, I am mapping through the seq twice, first to handle the first seq-pair and then to handle the second seq-pair. I thought of writing a function to like map within the map, but it was feeling too obscure. It felt like I was trading readability for terseness, but also felt like there must be an existing function that does exactly this. Thank you!

walterl00:11:03

Can't think of another core fn for this, or how to avoid maps in maps (especially with this data structure).

(mapv (fn [[ss is]] [(mapv str/upper-case ss) (mapv inc is)])
      seq-pairs)
... if the functions are fairly static, otherwise something like
(mapv (fn [[fx fy] [xs ys]] [(mapv fx xs) (mapv fy ys)])
      (repeat [str/upper-case inc])
      seq-pairs)

Martin Půda00:11:37

What about for and some destructuring?

(for [[v1 v2] [[["a""b""c"][1 2 3]]
               [["foo""bar""baz"][4 5 6]]]]
   [(mapv s/upper-case v1)
    (mapv inc v2)])

=> ([["A" "B" "C"] [2 3 4]] [["FOO" "BAR" "BAZ"] [5 6 7]])

👍 1
zach00:11:57

Ah, these are quite nice! I like the for loops readability a lot.

skylize05:11:01

Or something like this, perhaps.

(defn bimap [[f g][xs ys]]
  [(map f xs)
   (map g ys)])

(let [m [[["a" "b" "c"] [1 2 3]]
         [["foo" "bar" "baz"] [4 5 6]]]
      fs [str/upper-case inc]]
  (map #(bimap fs %) m))

👍 1
kennytilton10:11:10

I am uncomfortable with the rigidity of the "spec", specifically that each top element will be a vector of two vectors. If we are looking for a general approach, we would prefer a spec like "Given a sequence of vectors, apply item-wise a vector of transformations. Then we might write a more flexible:

(let [targets [[["a" "b" "c"] [1 2 3]]
               [["foo" "bar" "baz"] [4 5 6]]]
      xforms [str/upper-case inc]]
  (mapv (fn [target]
         (mapv (fn [v xform]
                (map xform v))
           target
           xforms))
    targets))

dang duomg 19107:11:17

how many arguments can a #() function have

dang duomg 19107:11:23

it doesn’t tell you the maximum number of arguments

dharrigan07:11:34

Good point, are you curious just to the maximum or something you're trying to solve?

tvirolai07:11:43

Normally Clojure functions can take up to 20 arguments. As #() should be just alternative syntax for fn , I'm guessing that applies to it too.

👍 2
dharrigan07:11:22

Yup, a quick glance through the source code seems that is the case

dharrigan07:11:54

Very interesting 😉

delaguardo07:11:03

#(apply + %&) same as normal Clojure function - any

dang duomg 19107:11:05

just for the sake of curiosity

delaguardo08:11:14

btw looks like this is clojurescript repl. mostly behavior is the same between Clojure and clojurescript but when you ask a question it is better to mention the platform. most people in this channel assume by default questions in this channel are about JVM clojure

dang duomg 19108:11:49

should i write a binding vector as [a 1, b 2]

delaguardo09:11:09

in compare to what?

delaguardo11:11:13

there is a clojure style guide - https://guide.clojure.style/

skylize13:11:35

I don't think you will find that many commas in the wild. If the pairs become too difficult distinguish without them, you are more likely to see, as @U4P4NREBY suggested, newlines used for separation.

dang duomg 19115:11:00

clojure macros aren’t hygienic 😢

delaguardo16:11:50

not automatically but there is syntax to expand a symbol to unique identifier

`(let [x# 42] (inc x#))
;; => (let* [x__149__auto__ 42] (clojure.core/inc x__149__auto__))
note that instead of x# you got x__149__auto__

andy.fingerhut16:11:41

And the backtick (`) behavior in Clojure is different than Common Lisp, IIRC, in that by default Clojure names are resolved and have their namespace added during expansion of backtick'ed forms, which goes a significant way in avoiding some of the issues that hygiene was meant to address. (I do not claim all issues, only some)

andy.fingerhut16:11:26

Rich Hickey knows about hygienic Lisp macros, but chose not to implement them in Clojure. Some brief background on this can be found in this talk transcript (or of course the video recording) here (search for "hygienic"): https://github.com/matthiasn/talk-transcripts/blob/master/Hickey_Rich/ClojureIntroForLispProgrammers.md

valerauko05:11:13

on new versions at least it also throws an error (warning?) if you have non-hygienic stuff

dang duomg 19116:11:05

are there any repls with structural editing support? there is replete repl on mobile which i really like is there one on the pc (preferably windows)?

lispyclouds16:11:06

I believe the strong recommendation is to use the REPL via connecting the editor to it rather than typing it at the prompt. Any reasons to prefer that?

lispyclouds16:11:04

most editors support eval via the REPL and the OS shouldnt be an issue there

dang duomg 19116:11:44

i already have nrepl and clojure sublimed installed lol thanks

lispyclouds16:11:23

awesome! with a proper editor+repl setup, you ideally never have to use the prompt 😄

skylize16:11:19

A common misconception is that "REPL driven development" means "typing into the repl". 😄 In reality, most devs most of the time will type into an editor, and then send individual forms to the repl for evaluation.

practicalli-johnny16:11:03

Rebel is a rich terminal Repl UI for Clojure, although it has docs and auto-completion other development features are provided by editors https://practical.li/clojure/clojure-cli/repl/ I use a terminal Repl for very minimal coding or for starting & restarting long running processes, e.g. developing APIs and other web services.

practicalli-johnny17:11:41

https://github.com/tonsky/Clojure-Sublimed looks like a fine editor for Clojure development https://practical.li/clojure/clojure-editors/ lists other Clojure editors available. There is a #clj-on-windows channel for help with running Clojure on Windows if problems arise

flowthing20:11:56

Since you’re already on Sublime Text, you could also try Tutkain (https://tutkain.flowthing.me), which comes with ParEdit for structural editing. (The downside, though, is that unlike Clojure Sublimed, Tutkain’s main developer is rather inept.)

Stuart23:11:55

I feel this is a really stupid question. But how to sort a list of strings alphabetically in clojurescript,. regardless of case ?

(sort ["BT" "beehive" "battle"]) => ("BT" "battle" "beehive") <<< WAT!
(sort ["bt" "beehive" "battle"]) => ("battle" "beehive" "bt")
?

Stuart23:11:25

This seems to work

(sort-by str/lower-case < ["BT" "beehive" "battle"]) => ("battle" "beehive" "BT")
(sort-by str/lower-case > ["BT" "beehive" "battle"]) => ("BT" "beehive" "battle")

👍 2
dumrat05:11:43

Didn't know sort-by had a 3 arity. That's cool.

💯 2