This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-02-24
Channels
- # announcements (5)
- # aws (5)
- # aws-lambda (6)
- # babashka (6)
- # beginners (48)
- # calva (54)
- # clj-commons (12)
- # clj-kondo (39)
- # cljfx (3)
- # cljs-dev (11)
- # clojure (91)
- # clojure-europe (25)
- # clojure-uk (3)
- # clojurescript (16)
- # cursive (2)
- # data-oriented-programming (6)
- # datomic (8)
- # emacs (10)
- # events (3)
- # fulcro (2)
- # functionalprogramming (2)
- # graalvm (4)
- # graphql (2)
- # helix (1)
- # honeysql (4)
- # jobs (1)
- # malli (4)
- # nextjournal (21)
- # off-topic (5)
- # other-languages (4)
- # overtone (3)
- # reitit (17)
- # releases (2)
- # rewrite-clj (6)
- # ring (6)
- # shadow-cljs (37)
I'm reading Structure and Interpretation of Computer Programs and doing the examples in Clojure. I want to recreate this procedure which returns a tree scaled by a factor. I don't understand why (scale-tree 2 10)
throws that Error
The procedure from the book
the first branch calls (empty? tree)
. on (scale-tree 2 10)
it is calling (empty? 2)
seqexp=> (empty? 2)
Execution error (IllegalArgumentException) at net.cgrand.seqexp/eval1715 (REPL:1173).
Don't know how to create ISeq from: java.lang.Long
seqexp=> (doc empty?)
-------------------------
clojure.core/empty?
([coll])
Returns true if coll has no items - same as (not (seq coll)).
Please use the idiom (seq x) rather than (not (empty? x))
nil
This function expects a collection and 2
violates tahtThis works, however the first condition doesn't seem very elegant. Is there a way to improve the first condition?
you can always make another function that has a more intention-revealing name and use it there
The next thing you might run into is using list? is usually a mistake in clojure, you want seq?
A while back i tried to do SICP in Clojure and it just really doesn't fit very well. I think just using chicken scheme, guile or MIT scheme is the best way to go
Off topic question: how many times did you learn SICP? I’m planning to do a second one in a couple of months 😄
I've gone through it two or three times. But I never finish. But I still get the charm

Might check out the series produced by code_report who did a series on SICP in Racket. Was a great way to follow along.
Sorry I’m a few days late…
One of the (several) reasons for not working through SICP in Clojure is that it’s not idiomatic at all. For instance, Scheme is frequently looking for an empty list, while most Clojure functions that return an empty list will use nil
punning instead. So it’s more common to use next
rather than rest
(for instance, this is what destructuring does… if you get to that part of Clojure).
Consequently, a more idiomatic approach might be:
(defn scale-tree
[tree factor]
(cond (nil? tree) nil
(not (sequential? tree)) (* tree factor)
:else (cons (scale-tree (first tree) factor)
(scale-tree (next tree) factor))))
That works, but testing is something is nil
and then returning nil
if it is, it something that is usually done with when
:
(defn scale-tree
[tree factor]
(when tree
(cond (not (sequential? tree)) (* tree factor)
:else (cons (scale-tree (first tree) factor)
(scale-tree (next tree) factor)))))
But that’s a cond
with only 2 branches, which is better served with an if
. This also means that the 2 conditions can switch places, and the not
can be dropped:
(defn scale-tree
[tree factor]
(when tree
(if (sequential? tree)
(cons (scale-tree (first tree) factor)
(scale-tree (next tree) factor))
(* tree factor))))
But at this point, I’d probably take advantage of the if
statement, and destructure once I know that it’s a sequential value:
(defn scale-tree
[tree factor]
(when tree
(if-let [[f & r] (and (sequential? tree) (seq tree))]
(cons (scale-tree f factor)
(scale-tree r factor))
(* tree factor))))
This looks totally different to the SICP version, even though it’s essentially doing the same thing!
The reason for me going through all of this wasn’t to show off (honest!) but to provide an example of why you’re better to learn the principles of SICP in Scheme, and once you are familiar with that, bring those skills into Clojure. Trying to apply Clojure directly to SICP can be an interesting exercise, but it may set you up with poor expectations on how to write Clojure.Thanks for the detailed response! I love these step by step on how to improve a piece of code. I took on @U03493LJW0H suggestions and I'm watching the code_report lessons as video is a format that I learn well too.
A line comment ;;
would be the only option for writing docs for a defrecord.
Alternatively, consider using a Clojure hash-map instead of a defrecord and add a clojure.spec if validation of values is required.
@lhing1112 defrecord
does not support docstrings. It creates a Java type and those can't have metadata like docs.
Hello everyone! I have a question regarding a function I wrote to check if something starts with quotes or not:
(defn another-func
[val]
(println "the val is:"val "and its type is: " (type val))
(if (and clojure.string/starts-with? val "\""
clojure.string/ends-with? val "\"")
(println "true value")
(println "false value")))
This is the only example I'd expect that will return true and it does
(another-func "\"5\"")
the val is: "5" and its type is: java.lang.String
true value
But, these also return true and I don't understand why, here are some examples:
(another-func 5)
the val is: 5 and its type is: java.lang.Long
true value
(another-func "5")
the val is: 5 and its type is: java.lang.String
true value
You should add () if you want to call a function
(starts-with? val "\"")
AAAHH, of course, thank you so much!
(also for the super fast reply, much appreciated!)
How opinionated is clojure in the "Pure" aspect of FP? In reading Clojure Applied, it seems IO and side effects are not rigidly restricted as in severely strict FP languages like Haskell. So to what degree does clojure attempt to be "Pure" outside of fundamentally immutable data structures?
Clojure is not Haskell. Clojure encourages and supports writing pure functions, and it is idiomatic, i.e. many functions in many widely-used libraries are pure functions. But there are no "pure function types" that are statically checked anywhere that require that one writes pure functions.
Unlike a language such as Java, Python, Ruby, JavaScript,where you have to go out of your way and against the grain of popular use to write pure functions.
Are there emacs/cider users, or are most people using VS Code or some other modern editor? I'm experiencing errors that cause Emacs to crash quite regularly, and that is something I've not experienced very often. Not sure what to make of it, whether its a cider issue, or something else.
people generally use whatever they want, there are tools for each editor. the actual numbers are can usually be found on the state of clojure yearly survey. here are last year’s results (Q16 is about dev environment) https://www.surveymonkey.com/results/SM-S2L8NR6K9/
if you have emacs questions, there’s an #emacs channel where you should be able to get some targeted help
I see, thanks Darin
Emacs has been used by the majority of Clojure developers as it has always had support from the early days. There are a wide range of editors that support Clojure https://practical.li/clojure/clojure-editors/
I use Prelude emacs (so Cider) for Clojure, works great with practically zero setup
Can you improve my code?
(defn
juxt-keys
"Return a new map, potentially with new keys added.
`juxtf` is called for each kvp and can return
either nil or a new kvp that will be 'assoc'ed into m."
[m juxtf]
(into
{}
(comp
(mapcat (juxt identity juxtf))
(remove nil?))
m))
;; use case
(comment
(let [timestamp-key? #{:fo}]
(juxt-keys
{:fo 1645712055012}
(fn [[k v]]
(when (timestamp-key? k)
[(keyword (str k "-iso"))
(.toString (java.time.Instant/ofEpochMilli v))]))))
{:fo 1645712055012, ::fo-iso "2022-02-24T14:14:15.012Z"})
Maybe with xforms https://github.com/cgrand/xforms/blob/master/src/net/cgrand/xforms.cljc#L87
(map #(.getName %) (.listFiles (File. ".")))
in this example, can't getName be "bare", I mean why do I need to wrap a function into an anonymous function, type inference?map
requires a Clojure function, e.g. something that implements the IFn
interface. getName
, the method on Java’s File
class, is not a function for Clojure
The .getName
is actually syntactic sugar for the “dot” special form for java-interop. Think of getName
as an argument for .
(this is an area we are looking at for Clojure 1.12)
grateful for the input 🙏
@U064X3EF3 I know this is such a little thing, but I run into it so often when doing java interop-y work. I’m so glad this is being looked into
@U064X3EF3...since I already asked once : ) and I've been mulling over how such an implementation would actually work. Is the clojure team looking at actually making it so that java methods will work as is or is there some other solution under consideration. And I understand nothing is cut in stone, just curious what direction the investigation is going...
not going to go into it here, it's more complicated than it appears, and is adjacent to other things we're considering.