Fork me on GitHub

how can i make a string of an expression bound in my namespace, including indentation and whitespace? i've taken a look at clojure.repl/source which is close to what i need, but it my case i want to inject the expression into a hiccup template (as a string) at the time of evaluation.


I wouldn't say such a thing is impossible, but at least the Clojure reader does not preserve this information. I think it will preserve the starting line and column in the input file of some selected expressions, but not all.


There are other libraries that can read Clojure code and/or EDN data and preserve other things that the Clojure reader does not.


hmm. it looks like i can leverage pprint for formatting. in which case, is it possible to read a def'ed expression as a string?

(defn my-func [] 1)

(fn->str my-func)
=> "(defn my-func [] 1)" 

Chris K10:04:08

any thoughts of learning clojure/functional programming before CS in uni? I am a highschool student and spend most of my programming time learning functional programming and clojure. I kinda fear that learning clojure and functional programming might mess me up for CS in uni, because I believe they are more based on lower level and imperative langauges. Any thoughts on this? (I hope this is a valid question for the beginners section)


i'm sure a lot has changed since i was at university, but one common theme of nearly all the languages i remember using was that they were strongly typed, which of course we don't see in Clojure. in my opinion it's worth learning any strongly typed language at a basic level just because they're unavoidable in the real world, and especially at uni. but focusing on Clojure certainly will not "mess you up" for a CS degree, and in fact you might find yourself writing better object oriented code with reduced state because of your exposure to Clojure / LISP.

Chris K13:04:47

oh I see so basically what you are saying is that by learning functional lisp programming, I would actually be able to write better OOp code


I think it's a great idea to learn Clojure before a CS program. as @U0GC1C09L said, it'll improve your understanding of coding principles. Lower level stuff you can pick up easily. Basically, you need to name every drawer where you keep something, and different things can manipulate the drawers without other things knowing. This is unsatisfactory for sanity. However, it is the decades-long norm in CS. I think it's easy to pick up this habit later, and I don't know why you would want to 😄 If you are doing low-level device programming, sometimes you have not the clock cycles to spare, but Church-Turing should give you confidence that anything you can do with a lisp you can do with imperative and vice versa, it's just taking into account psychic peace that draws a clear victory line for me.

Chris K13:04:02

wow this answer is great thxs


knowing Clojure might also make you the hippest kid in your class 😎

😎 1
Bill Phillips17:04:13

Chris, my first serious programming instruction was done in Scheme in college, and it was wonderful. It expanded my mind and exposed me to new things, and the following semester I was writing linux networking code in C! I also have a friend who learned programming with Lisp in high school, and it was a formative experience for him, too. You are learning cool things and they’re fun! There’s NO downside to that AT ALL. 🙂 I have never ever ever met anyone who ever said “I regret having fun learning a cool unusual programming thing”

Chris K10:04:59

@U010GL90FN0 Thxs for your answer! I already thought that lisp is such a cool language, and now I'll just keep going 😄

Nate Guerin17:04:48

For what it's worth, I help teach courses in a top-ten CS program, and we teach scheme as well. LISPs are nice when saying things about the mathematical properties of computer programs

Chris K00:04:55

Hmm. I heard that a lot. Of how lisp is good for mathematical representation, but I didn't quite get it because, when you write inside parentheses and with prefix notation, it doesn't look like the conventional mathematical notations we usually see. I know notation and the styling isn't rly anything but would it be ok for you explain that a little bit? Thxs @U0120B5AN2W

Nate Guerin00:04:56

Sure. The notation doesn't really matter. It's more because of the properties of referential integrity ( and because you can prove things about them using mathematical induction.

Nate Guerin00:04:08

It's hard to prove things about programs where the state varies all of the time.

Chris K11:04:11

Oh I see. So basically immutabilty, pure functions, and the things you talked about mathematical induction and referential transparency makes this better clojure better than other languages with mutable data types

Chris K11:04:24

That's cool I didn't know that Thxs 😄


I don’t think it will mess you up. If you want to get a CS degree, you should learn more than one style of programming, even if not all styles are equally used or productive


It may make you annoyed at having to do projects in language styles that you do not prefer, but hopefully you can view those as part of the learning process


Why does calling flatten on a set or map return the empty list unlike when calling it on vectors and lists?


flatten only works on sequential collections (as mentioned in the docstring)

👍 1

You can have a flatten that works on all collections by substituting sequential? for coll? in the source.

(defn flatten- [x] (filter (complement coll?) (rest (tree-seq coll? seq x))))

Patrick Truong18:04:06

Hello everyone, I’m working on a basic Reagent project using just shadow-cljs. I’m using cider nrepl and VS Code Calva. On my main app file, I have a simple atom for toggle:

(ns alpha-journal.core
   [reagent.core :as r]
   [reagent.dom :as dom]))

(def toggled (r/atom false))

(defn app []
  [:div {:class [(when true 'bg-red-500) 'h-screen]}
which is referenced in the app component. However, when I used my repl and lookup any variables or functions, it gives me the value, but also gives me a warning:
alpha-journal.core=> @toggled
------ WARNING - :undeclared-var -----------------------------------------------
 Resource: :1:2
 Use of undeclared Var alpha-journal.core/toggled
What does this warning mean? Why are my variables considered undeclared? How can I get fix this warning? Thanks for all the help 🙂


#reagent channel will be able to help much faster.

👍 1

How did you set your repl namespace?

Patrick Truong19:04:37

@U11BV7MTK I don’t think I did explicitly? My shadow-cljs.edn looks like this

{:deps   true
 :builds {:app {:target     :browser
                :output-dir "public/out"
                :asset-path "/out"
                :modules    {:main {:init-fn alpha-journal.core/main}}
                :devtools   {:http-root "public"
                             :http-port 8020}}}}
and my startup log shows shadow-cljs - nREPL server started on port 59071 That is then the port I connected to via Calva

Patrick Truong19:04:27

@U11BV7MTK then in Calva I switched namespace to my main file:

cljs.user=> (ns alpha-journal.core)


Your repl prompt shows alpha-journal.core


I’m wondering how you set that


Ah that’s why


You created a new ns


Rather than going into the one defined


Restart your repl and use require and then in-ns


Otherwise you’re defining a new namespace

Patrick Truong19:04:51

Gotcha, thanks I’ll try that out now

Patrick Truong19:04:28

@U11BV7MTK Thanks! that fixed it. Quick question, is there any particular reason why I have to use the delayed eval quote for my namespace: (in-ns 'alpha-journal.core) vs (in-ns alpha-journal.core) ? Thanks for all the help once again


It’s not delayed eval. If you eval a random symbol it tries to look it up in the environment and errors if it’s not defined


The quote makes sure we are talking about the symbol rather than what that symbol resolves for


Think the symbol ‘+ versus the function “add” which it points to in the environment


Make sense?


So there is no var defined as alpha-journal.core. We’re using the symbol itself

Patrick Truong19:04:15

Got it, thanks for the clarification, helps clear up a lot about the use of quote in general 🙂



Timofey Sitnikov21:04:25

Why do I get?

[I] /home/sporty/clojure/dbt~> clj -Amigrate up
Applying 003-zet
Execution error (NullPointerException) at migrate/-main (migrate.clj:10).

Full report at:
When I run the following file with the up argument?
1 (ns migrate (:require [ragtime.jdbc :as jdbc] [ragtime.repl :as repl]))
    3 (def config
    4   {:datastore
    5   ¦(jdbc/sql-database {:connection-uri "jdbc:sqlite:resources/db.sqlite"})
    6   ¦:migrations (jdbc/load-resources "migrations")})
    8 (defn -main [ arg ]
    9   (case arg
   10   ¦ "up" ((repl/migrate config))
   11   ¦ "down" (repl/rollback config)))
Notice that I do not get this issue when the case keyword is not used.

Timofey Sitnikov21:04:02

Oops nevermind, it's hard to let go of C++ and realize that it is all data, below works.

8 (defn -main [ arg ]
    9   ((case arg
   10   ¦ "up" repl/migrate
   11   ¦ "down" repl/rollback) config))

Sergiusz Bleja21:04:32

I'm trying to evaluate someone elses code which uses clojure.core.matrix. Line 3 attempts to set index 100 to 1 but fails. I'm guessing the functionality has changed, but I can't find the way to do it. How can you set the value of a vectorz ?

John MacIsaac23:04:46

I am working my way thru the book, “Clojure for the Brave and True”. And I am stuck on a problem in chapter 4 ( The problem is to convert a CSV string into a sequence of vectors and then into a sequence of maps. I am stuck in in mapify function.  I dont understand where the  ARGS  for the PARAMS of its second anonymous function come from. The fifth line from the bottom of the code snippet pinpoints the parameters.  

(ns fwpd.core)
;(def filename "suspects.csv")
;(slurp filename)

(def suspects "Edward Cullen,10\nBella Swan,0\nCharlie Swan,0\nJacob Black,
3\nCarlisle Cullen,6\n\n")

(defn parse
  "Convert CSV into a seq of vecs, into rows of columns ([name num] [name num] ...)"
  (map #(clojure.string/split % #",")
       (clojure.string/split string #"\n")))

(map #(str->int (second %))
     (slurp filename))

(defn str->int [str] (Integer. str))
(def vamp-keys [:name :glitter-index])
(def conversions {:name identity :glitter-index str->int})
(defn convert [vamp-key value] ((get conversions vamp-key) value))

(defn mapify
  "Convert a seq of vecs into a seq of maps, & convert num-strings to numbers:
  ([\"Edward Cullen\" \"10\"] ...) to ({:name \"Eward Cullen\" :glitter-index 10} ...)"
  (map (fn [unmapped-row]
         (reduce (fn [row-map [vamp-key value]]
                   (assoc row-map vamp-key (convert vamp-key value)))
                 (map vector vamp-keys unmapped-row)))

(mapify (parse suspects))

; "Edward Cullen,10\nBella Swan,0\nCharlie Swan,0\nJacob Black,3\nCarlisle Cullen,6\n\n"
; INTO THIS (via parse):
;(["Edward Cullen" "10"]
; ["Bella Swan" "0"]
; ["Charlie Swan" "0"]
; ["Jacob Black" "3"]
; ["Carlisle Cullen" "6"])
;; AND THEN INTO THIS (via mapify):
;({:name "Edward Cullen", :glitter-index 10}
; {:name "Bella Swan", :glitter-index 0}
; {:name "Charlie Swan", :glitter-index 0}
; {:name "Jacob Black", :glitter-index 3}
; {:name "Carlisle Cullen", :glitter-index 6})
;; NB vecs -> maps & string-values -> number-values

; Re: mapify
; This:               (map vector vamp-keys ["Edward Cullen" "10"])
; evaluates to this:  ([:name "Edward Cullen"] [:glitter-index "10"])
;            [row-map [vamp-key value]]?
;(reduce (fn [row-map [vamp-key value]]
;          (assoc row-map vamp-key (convert vamp-key value)))
;        {}
;        ([:name "Edward Cullen"] [:glitter-index "10"]))


@johnmi A little experimentation with reduce on a different function may be helpful to understand.

user=> (defn print-args-then-conj [x y]
(println "x=" x "y=" y)
(conj x y))
user=> (reduce print-args-then-conj [] [5 7 11 13])
x= [] y= 5
x= [5] y= 7
x= [5 7] y= 11
x= [5 7 11] y= 13
[5 7 11 13]


Also the doc string for reduce , which you can see via (doc reduce) at a REPL prompt, may be useful?

John MacIsaac23:04:47

Thank you @andy.fingerhut. I just discovered that there is a channel for #bravendtrue and will move my question and your answer over to it. And will close the question for this channel.


No problem. Your question is definitely relevant for the #beginners channel, too

John MacIsaac23:04:46

I just dont want abuse slackers with duplicate postings. Altho beginners probably gets more traffic. thanks again.