Fork me on GitHub

for it seems like the alias-uri mappings only apply when emitting xml, is there something similar for the inverse? i.e. when parsing instead of getting #...Element{:tag :xmlns.abcxyz/tagName} I could get #...Element{:tag ::my-alias/tagName}?


Easiest way to dockerize a Clojure application?


I have a k8s instance already


make an uberjar, put it into a java container running java -jar $yourjar.jar as the docker CMD


no need to use "clojure" docker images


any of the adoptopenjdk images will suffice


For this 4Clojure problem interleaving two sequences I came up with:

(fn [coll-1 coll-2]                                                         
  (flatten (into [] (zipmap coll-1 coll-2))))
Which works in my editor/repl for all the tests but fails on the first test in 4clojure with a "Failed the unit tests" error. Can't figure out what I'm doing wrong.


4clojure uses an old version of clojure (1.4 or 1.5)


I looked at the source of all 3 core functions and the latest was flatten added with 1.2


doesn't it tell you which unit test failed?


btw the puzzle can be solved with two functions and no parens


It fails right on that first one. I copied over the unit tests to my editor and all come out true


yeah that breaks on clojure 1.4


clj -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.4.0"}}}'


to try it ^


user=> (def x (fn [coll-1 coll-2]
  (flatten (into [] (zipmap coll-1 coll-2)))))
user=> (= (x [1 2 3] [:a :b :c]) '(1 :a 2 :b 3 :c))
user=> (x [1 2 3] [:a :b :c])
(3 :c 2 :b 1 :a)


Oh, that is a neat way to try on old versions. Ok.


4clojure is bizarre


oh I see what broke


good problems, but the execution infra is old


maybe @U04V15CAJ has a good way to sandbox code for a fresher 4clojure experience


babashka is already used for 4clojure problems in the shell: sci (the interpreter on which babashka builds) also has sandboxing options


the hash map has no defined order


Yeah if I reverse the sequence before passing it to flatten it all passes


btw flatten is terrible


it makes me flinch when I see it :D


How do you approach it?


I have a collection of videos that walk through how I though about and solved in different ways the first 60 challenges on 4Clojure. I encourage you to try the relevant challenges before looking at the video that covers those challenges 🙂


Nice! I have about 50 solved so far so I'll start checking these out


to elaborate a bit, flatten can shred through multiple levels of things


and people abuse it to achieve a single-level splice


@chase-lambert due to 4clojure's substitution model, this works mapcat list


Yup, I'm reading that in the saved solutions now. You are one of my saved people btw


yeah, for a single level, you usually want concat (or something similar like cat or mapcat )


(map vector [a b] [1 2]) -> ([a 1] [b 2]) -> (apply concat that) (a 1 b 2)


you can leverage the fact that map can take multiple collections


and apply a function "slicing" an item from all the collections in parallel

Igor Lenterman01:07:43

Hey guys! Been reading about Clojure a lot online and have decided to invest the time and effort in learning. Anywhere you would recommend starting? What is the fastest way to learn Clojure? What is the most enjoyable way to learn Clojure?


You may find the books and video guides I created useful I recommend finding a Clojure aware editor you like using. I use Spacemacs but there are several common editors that support Clojure I learned a lot about the core functions in clojure by doing challenges. There is a playlist of videos about that on the practicalli website. There are lots of tutorials on the internet on how to build things in Clojure. I am adding more to the books over the coming months, so let me know if you are looking for something specific. Good luck.

👍 6

@U05254DQM, a video series on connecting to a db (SQL or Postgress) in a clojure'y way, doing selects, inserts etc would be great! I'm finding it hard to find good sources on this.


@U013YN3T4DA Thanks for the suggestion, it's a very useful topic so I'll move it up my (very long) Todo list. I have some basic content in the Practicalli webapps book, but it's very simplistic and needs updating. Many people use SQL fairly directly so next.jdbc seems a great project to use and I'll probably pick Sean Cornfield's brain on this. also seems a nice tool. I also like to use migrations with SQL too.


Take a look at the docs, the look very useful and have many examples


Thanks for these links! I'll have a read. THis has been a big stumbling block for me in Clojure, I think not being familiar with java doesn't help It's frustrating as in C# (my day job) accessing a db is really simple. I've noticed that with Clojure, it can take stuff that is quite hard in other language and make it so simple, yet some of the stuff that is simple that I don't have to think about in C# seem quite hard. Guess that will evaporate over time as I get more familiar with Clojure and what the popular / default packages are.


I see you are doing a series on CI, I think that will be very helpful!


namely, vector


Sounds good! Thank you

Alex Miller (Clojure team)01:07:29

@igor.lenterman there truly is no one answer to any of those questions - everyone will find different material to connect with

Alex Miller (Clojure team)01:07:46

many people like Clojure for the Brave and True as a fun intro

Igor Lenterman01:07:32

any projects you would recommend a beginner to practice building?

Alex Miller (Clojure team)01:07:33

it's free online or you can buy it in paper form

Igor Lenterman01:07:42

I prefer building to reading for learning code

Alex Miller (Clojure team)01:07:13

simple games are often a good starting point for me - rock paper scissors, etc


babashka is already used for 4clojure problems in the shell: sci (the interpreter on which babashka builds) also has sandboxing options


Also, unrelated to babashka/sci, but related to 4clojure: I do have a slightly updated version of clojail here:


@igor.lenterman, there is also codewars.;r[]=-8&amp;beta=false You can specify just to show kata that have clojure solutions. A nice thing here is once you solve the problem in clojure you get to see other peoples solutions and some are voted on best practice so you can often learn new techniques just by looking at others solutions.

Igor Lenterman17:07:03

Thank you! Excited to jump in


Codewars has a lot of mathematics oriented challenges, where you need to be able to recognise the maths techniques from the minimal description. There is also which feels like a wider range of challenges. And helps you learn the clojure.core functions.


You can start off at 8 KYU (the easiest puzzles) and work your way up to 1 KYU, some of which can be very hard puzzles


(defn my-reduce
  ([f initial coll]
   (loop [result initial
          remaining coll]
     (if (empty? remaining)
       (recur (f result (first remaining)) (rest remaining)))))
  ([f [head & tail]] --> ?
   (my-reduce f head tail)))
I'm having a little bit of trouble understanding the line marked with a question mark here. Anyone have any insight? I know that we start with a function definition which takes parameters f initial and coll, then we initialize a loop with result bound to initial and remaining bound to coll, if what's remaining in our collection is empty then return the result else we recur using the result of applying the function to the initial value and the first item of what's remaining? But, the lines after are a little confusing


(defn ([x] ...) ([x y] ...)) defines a function with two bodies, and one is picked based on the count of the argument list


so we have here, if we ignoring destructuring: (defn ([f init coll] ...) ([f init-and-coll] ...))


then the destructuring [head & tail] uses one element as the "init" and the ones after as the coll


by a self call


hope that helps


So the first time we execute the second block to set init and tail and the first block handles breaking down until remaining is empty?


right - we call what you call "blocks" the bodies of the function


ahhh ok i see


first clojure invokes the body matching the count of the arg list, then it can self-call (that's the most common pattern in multi-arity code)


yes i forgot all about the arity stuff


ok it makes more sense now


sometimes functions have totally different code is invoked (see map for example) but that's more rare

👍 3

Hi guys, here is a question that’s been bugging me for 3 weeks.. I’ve parsed the output generated by tree (with json output) and here is what the datastructure looks like: a Vector containing 1-n Maps:

[{:type "directory",
  :name ".",
  [{:type "directory",
    :name "Intro",
    [{:type "file", :name "01 What The Program is About and How to Do It.mp4"}
     {:type "file", :name "02 How Training Works 5PS.mp4"}]}
   {:type "directory",
    :name "Session 01 - Fundamentals",
    [{:type "directory",
      :name "01 Prepare",
      [{:type "file", :name "01 Standing Knee to Chest.mp4"} {:type "file", :name "02 Single Leg Deadlift.mp4"}]}
     {:type "directory",
      :name "02 Practice",
      [{:type "file", :name "01 General Kneeling Lunge.mp4"} {:type "file", :name "02 Modified Pigeon Stretch.mp4"}]}
     {:type "file", :name "Let's Get This Started.mp4"}]}]}]
I know this is a tree structure and I need some kind of recursion to parse it


ultimately i want to generate html using hiccup from this, but i can’t seem to ‘crack’ the puzzle


i’ve try’d many things, the latest:

(defn process-tree [vec-with-maps]
  (map (fn [{:keys [type name contents]}]
           (= "directory" type) (do
                                  (println (str "dir:" name))
                                  (when contents
                                    (process-tree contents)))
           (= "file" type) (println (str "file: " name))))

(process-tree json-parsed)


the problem with this besides the side effects


is that it first does the directories before the files in the :contents


Should I go at this completely differently and use something like a Walk or Zip


or am I just not ‘getting’ recursion?


a recursive function that eagerly walks to the bottom, then builds a data structure from the bottom up should work


as you go down, keep a stack of each level you visited


as you go up, return a "clojurization" of the item you are visiting to your parent, using the clojurized results your children passed back via that stack


do you know of an example where i could sneak peak at, as this makes sense, i just have no clue how to do it


sounds like I would reduce the tree structure into some other type of data structure and then ‘step through’ it?


what I'm talking about is how to make that data structure


if all you want is to process it for side effects, use tree-seq


(tree-seq :contents seq ...) - that will give a lazy-seq of every node


then you can map across the top level of each node, knowing you'll only hit each one once


that looks interesting



(ins)user=> (map :name (tree-seq :contents :contents dirs))
(ins)user=> (map :name (tree-seq :contents :contents (first dirs)))
("." "Intro" "01 What The Program is About and How to Do It.mp4" "02 How Training Works 5PS.mp4" "Session 01 - Fundamentals" "01 Prepare" "01 Standing K
nee to Chest.mp4" "02 Single Leg Deadlift.mp4" "02 Practice" "01 General Kneeling Lunge.mp4" "02 Modified Pigeon Stretch.mp4" "Let's Get This 
(ins)user=> (pprint *1)
 "01 What The Program is About and How to Do It.mp4"
 "02 How Training Works 5PS.mp4"
 "Session 01 - Fundamentals"
 "01 Prepare"
 "01 Standing Knee to Chest.mp4"
 "02 Single Leg Deadlift.mp4"
 "02 Practice"
 "01 General Kneeling Lunge.mp4"
 "02 Modified Pigeon Stretch.mp4"
 "Let's Get This Started.mp4")


(where dirs is literally what you pasted)


I think that hit everything correctly, you should double check of course


this is great stuff and so much easier 🙂


that's a common experience with clojure - the right function turns your problem into a non-problem


the data structure / data manipulation libs just do most of the work


now i just want to generate h1 for directories and ul/li for files with hiccup and i’m done


nice, so you just replace (map :name ...) with a a map of some function looking at type plus name and returning an h1...


sounds simple


you'd want to modify that code slightly if you ever had more than one hash-map in that top level vector


maybe it would be better to construct {:contents dirs} instead of calling on (first dirs) - that less likely to break in the future while offering the same behavior


this is a sample of the full directory layout


it does still start with the (first dirs)


i got 1 part working ha:

(defn directory-to-html [name]
  (html [:h1 name]))

(map #(directory-to-html (:name %)) (tree-seq :contents :contents (first dirs)))


i think i got it:

(defn directory_or_folder [type name]
    (= "directory" type) (directory-to-html name)
    (= "file" type) (file-to-html name)))

(map #(directory_or_folder (:type %) (:name %)) (tree-seq :contents :contents (first dirs)))


with helper functions:

(defn directory-to-html [name]
  (html [:h1 name]))

(defn file-to-html [filename]
  (html [:li filename]))


1 thing that is ‘wrong’ is that the sublevel is not really ‘saved’


right - there's nothing that tracks that in the current code


would it be too difficult to fix this?


maybe somehow sort the data structure so that files come before directories?


right - replace the second :contents with a sort - that might suffice


err, with something that accesses :contents but sorts files first that is


but if different nestings carry different meanings, you'll need something else I think - maybe something tricky where the second instance of :contents (that is the function that returns the children) also looks at the current level, and increments the level of each child...


i will try, i think for now I will keep it simple


(defn children-of
  [{:keys [level contents] :as el}]
  (->> contents
       (sort-by :type)
       (map (fn [c] (assoc c :level (inc level))))))
(ins)user=> (map (juxt :name :type :level) (tree-seq :contents children-of {:contents dirs :level 0}))
([nil nil 0] ["." "directory" 1] ["Intro" "directory" 2] ["01 What The Program is About and How to Do It.mp4" "file" 3] ["02 How Training Works 5PS.mp4"
 "file" 3] ["Session 01 - Fundamentals" "directory" 2] ["01 Prepare" "directory" 3] ["01 Standing Knee to Chest.mp4" "file" 4] ["02 Single Leg Deadlift.
mp4" "file" 4] ["02 Practice" "directory" 3] ["01 General Kneeling Lunge.mp4" "file" 4] ["02 Modified Pigeon Stretch.mp4" "file" 4] ["Let's Get This Sta
rted.mp4" "file" 3])
(ins)user=> (pprint *1)
([nil nil 0]
 ["." "directory" 1]
 ["Intro" "directory" 2]
 ["01 What The Program is About and How to Do It.mp4" "file" 3]
 ["02 How Training Works 5PS.mp4" "file" 3]
 ["Session 01 - Fundamentals" "directory" 2]
 ["01 Prepare" "directory" 3]
 ["01 Standing Knee to Chest.mp4" "file" 4]
 ["02 Single Leg Deadlift.mp4" "file" 4]
 ["02 Practice" "directory" 3]
 ["01 General Kneeling Lunge.mp4" "file" 4]
 ["02 Modified Pigeon Stretch.mp4" "file" 4]
 ["Let's Get This Started.mp4" "file" 3])
one stab at it, it's an interesting problem


all directories are before sibling files so the sort is opposite of what you want


but see how it accurately shows levels at least


by mapping a function that adds 1 to the level of the parent


wow that is awesome


you could use a similar approach to give each one an href link back to its parent, or to make an adjacency list that allows reconstructing the full form (with optional cycles) out of the "flattened" form here


all those things require is a unique id generator


(and a slight modification to the map fn of course)


thank you so much for your help


i’m a beginner at this


and this gets me started big time 🙂

Pavel Klavík20:07:49

while using tree-seq seems nice (I didn't even knew it existed), I would also recommend as a learning exercise to do it without it, so you know how to write this using plain recursion


How would you approach this @pavel.klavik as I was thinking the same thing after first getting a basic version working


i’m a beginner and i tried various approaches i got from books/internet but nothing got me actually there while it seems so simple


Here’s how I drew the diagram:


that diagram accurately describes how to descend, but doesn't describe how to create a result as you do so

Pavel Klavík21:07:15

I would start with thinking how it would work outside Clojure. What should each step do? If I assume that I already have a step as a black box, how their answers can be composed.