This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-12-10
Channels
- # adventofcode (174)
- # announcements (5)
- # aws (9)
- # babashka (17)
- # beginners (259)
- # boot-dev (1)
- # calva (6)
- # cider (19)
- # circleci (7)
- # clj-kondo (9)
- # cljfx (51)
- # cljs-dev (4)
- # clojure (83)
- # clojure-australia (2)
- # clojure-dev (9)
- # clojure-europe (78)
- # clojure-nl (3)
- # clojure-spec (4)
- # clojure-switzerland (1)
- # clojure-uk (18)
- # clojurescript (22)
- # conjure (17)
- # cursive (17)
- # data-science (1)
- # datomic (15)
- # defnpodcast (1)
- # events (2)
- # fulcro (39)
- # graalvm (16)
- # graphql (1)
- # kaocha (5)
- # lambdaisland (11)
- # malli (6)
- # meander (1)
- # off-topic (26)
- # pathom (10)
- # re-frame (10)
- # reitit (6)
- # rewrite-clj (7)
- # sci (3)
- # shadow-cljs (28)
- # sql (12)
- # test-check (10)
- # tools-deps (31)
Hello everybody, Clojure noob here. I have been kicked off 4Clojure Android app and can't login to my user anymore, however credentials are correct and he browser access goes smooth as usual. Has anyone experienced the same behaviour? Thanks sincerely in advance!
oke, and another problem
(defn isPrime? [n known]
(loop [cnt (dec (count known)) acc []]
(if (< cnt 0) (not (any? acc))
(recur (dec cnt) (concat acc [(zero? (mod n (nth known cnt)))])))))
(defn my_primes
"my version to print out primes to a certain number"
[limit]
(map #(isPrime? % []) (range 2 .. limit ))
)
error :
; Syntax error compiling at (chapter4.clj:32:26).
; Can't take value of a macro: #'clojure.core/..
You don't need the ..
in your range function, and in fact ..
means something else in Clojure
Just do (range 2 limit)
and there is another error. I was hoping on seeing all the prime-numbers but I see now a collection of false 😢
you want filter
not map
I would say test your isPrime?
function first and make sure it returns true
when you give it a prime number and false
(or nil
) when you give it a non-prime number.
I tried that one also but then I see a empty collection. So I assume my isPrime is wrong.
what do you think of my solutions . I did only study the 4 first chapters of the Clojure from the ground up site
https://github.com/RoelofWobben/Learning_in_public/blob/main/ground_up/src/ground_up/chapter4.clj
The code looks good overall. A couple style points: you are using partial
correctly, but there was a discussion recently about using (partial foo)
versus using #(foo %)
and a lot of folks favor using #(foo %)
in most cases because it’s more versatile and also slightly more efficient. Also it’s idiomatic to use shorter names like coll
and pred
instead of spelling out collection
and predicate
(though I favor using longer, more explicit names personally, except for really common terms like coll
and pred
).
so If I understand you well I could change this (partial divisible? n)
to #(divisible? n)
?
You need to add the %
at the end
but yeah, that’s what I was referring to
Right
Oh, and it’s also conventional to use dashes in names instead of underscore.
so count-occurences
instead of count_occurences
, and my-filter
and my-primes
Clojure folks are too lazy to hold down the shift key 😄
It’s actually the same number of parens in a lot of cases, it’s just that the first paren comes to the left of the function name instead of to the right.
Just like HTML does with <
and >
.
I hope i once learn as much clojure I can make a website with it and solved the difficult challenges of Advent of Code or exercism
Macros can be really hard to wrap your head around, but honestly I've been using Clojure for years and years, and I've written maybe 3 macros total (not counting "let's write a macro!" exercises)
Using the threading macros, find how many numbers from 0 to 9999 are palindromes: identical when written forwards and backwards. 121 is a palindrome, as is 7447 and 5, but not 12 or 953.
Write a macro id which takes a function and a list of args: (id f a b c), and returns an expression which calls that function with the given args: (f a b c).
Write a macro log which uses a var, logging-enabled, to determine whether or not to print an expression to the console at compile time. If logging-enabled is false, (log :hi) should macroexpand to nil. If logging-enabled is true, (log :hi) should macroexpand to (prn :hi). Why would you want to do this check during compilation, instead of when running the program? What might you lose?
Yeah most of the time a good function is all you ever need. Plus you can't pass a macro around like you can a function.
Two of those require you to write your own macro; the first one just wants you to use some of the built-in macros.
Just remember: macros write code, they don't do anything to your runtime data.
A macro is a tiny program that writes bits of other programs.
we see tomorrow. I hope I can ask for help here if needed or for a review. I hope I will not ask for help too much but the error messages are for me not always clear and as I said im totally new in Clojure so I think I need a lot of help to learn it wel
Yeah, the error messages are a sore spot but they're getting better, and after a while you kind of get to recognize patterns of "Oh, I got this kind of error message, I should check, that"
but some of them stump even the best of us.
Yeah, that's a good use for a macro.
"Build Your Own defn
" 🙂
sorry I mean this one :
Write a macro id which takes a function and a list of args: (id f a b c), and returns an expression which calls that function with the given args: (f a b c).
You’ll need to add some macro-specific syntax to that so that it doesn’t just execute (fun a b c)
when you call it, but that’s actually a good start: you’ve written out what you want the end result to be when your macro executes, and now you just have to convert it into the body of an actual macro.
hmm, the only thing I can find it to change it into this :
(defmacro id [fun a b c]
(fun a b c)
``
You’re short a )
at the end, but once you add that, try running in your REPL with (macroexpand '(id foo a b c))
Then try (macroexpand '(id + 1 2 3))
on both I see this in repl
clj::chapter4=>
(chapter4/fun chapter4/a chapter4/b chapter4/c)
For the second one you should see (+ 1 2 3)
, (possibly with the clojure namespace attached to the +
symbol). So there’s something not quite right with your macro.
you need unquotes
you are currently putting a literal symbol a b c in the expanded code
yeah sorry, that too
(defmacro id [fun a b c]
`(fun ~a ~b ~c))
gives now with :
(macroexpand '(id + 1 2 3))
You’re getting closer
If you want a challenge, you could try to modify your id
macro so that it takes zero or more arguments.
A macro without a syntax quote?? 😱
Heh, I can see how to do that but still 😱
Close, you need a slightly different unquote for the args
bit
Do you have a reference/tutorial for defmacro
? It should show you the list of unquote symbols.
I onu have this page : https://aphyr.com/posts/305-clojure-from-the-ground-up-macros
have you tried ~@args
?
the @
essentially is apply
for macros
That’s the “unquote-splice” symbol, btw, and notice it’s @
not &
a macro is literally just a function that takes code (as a data structure) and returns replacement code (as a data structure)
so you just want a function that does: (id + 1 2 3) -> (+ 1 2 3)
args is a seq (1 2 3) so you're almost there. how do you prepend something to a list?
there you go (or cons)
(defmacro id [fun & args]
(conj args fun))
or
(defmacro id [fun & args]
(cons fun args)) ;; order is different
people often think that macros are this special thing in clojure that needs syntax-quote and vice versa, but macros are literally just functions, and syntax-quote is literally just a templating syntax for data
Time to make a lot of notes and take a break. Tomorrow further on this for me unknown territory
you can find examples of both styles in clojure core
look at (source when)
or (source and)
for a couple good examples to study
hmm, in your examples source is unknown when I do it in repl @alexmiller
a good exercise is also to forget about defmacro
and just implement normal functions with defn
, and just invoke the function with quoted arguments manually (e.g. (foo 'bar '1 '[1 2 3])
instead of (foo bar 1 [1 2 3])
)
then to turn foo
into a macro you just need to remove the quotes from the invocation and replace defn
with defmacro
you might need to (use 'clojure.repl)
if you're not in user namespace
source
is in clojure.repl
you're almost done
:thumbsup:
it's all just more functions
Most people who have used the Brave & True book have been pleased with it
there’s also a #braveandtrue channel here specifically for that book/website
and I have to learn a framework if I want to make websites and learn how to store something in a database
It took me a few months to get really comfortable with Clojure, but that was back before Slack and also I was new to the whole “functional programming” thing.
I tried to start using Clojure when it was really new, but the lack of leiningen, etc., at the time made it too painful to be productive, and gave it up for a couple of years. Then came back to it when the tooling was much improved.
Yeah, leiningen was a big help at the time.
I had been using Ocaml quite a bit before Clojure, so same here regarding the functional aspect.
I think in the future I will have the most problems when I want to use something as reframe. Never wrote javascript or react or something before
I love re-frame, but yeah react does have a few quirks, and also cljs isn’t 100% identical to clj, so there’s bits that may bite the unwary. I’m working full time doing clj+cljs+re-frame tho, so there’s more than plenty enough to get a decent web app up and running.
im thinking if and when I got to that point to make a website which uses the Rijksmuseaum api . where someone sees a page and in the same time the images are downloaded and they replace the placeholders
Hmm, I’ve done that in straight JS back in the day, never tried to do in cljs :thinking_face:
replace placeholder images with hi-res versions that is
is there then a big difference in cjs and reframe. The way the clojurefarm is teaching us clojure is using reframe
Re-frame is a library that uses CLJS. It’s not part of Clojure or CLJS, it’s just popular.
Basically, React exists in the world of JS, and someone wrote a CLJS library named “reagent” to make it easier to use React in CLJS, and then someone else wrote a library named “re-frame” on top of reagent.
first this "book", then the brave book and then 4 clojure and then I think things like reframe i have to learn
maybe I come tomorrow or later back to see how to solve this one :
Advanced) Using the rationalize function, write a macro exact which rewrites any use of +, -, *, or / to force the use of ratios instead of floating-point numbers. (* 2452.45 100) returns 245244.99999999997, but (exact (* 2452.45 100)) should return 245245N
Greetings! Can't find an elegant way to do a partial flatten, by which I mean a function that accepts any nesting of sequences and returns a sequence of the innermost sequences ; e.g. (partial-flatten [[[1 2]] [[[3 4]]]]) => ([1 2] [3 4]
.
Could a kind puzzle-inclined person help me out?
but I only want to flatten n levels, I only want to flatten when the lists don't contain x, etc
in general flatten get used when you write a program of the form 1. do some stuff that builds up some nested list 2. flatten things out
but while step #1 is a generally steeped in context, by the time you get to step #2 the context has been thrown away, so determining how and where to flatten has to be done all over again
while if you just applied concat here and there while doing #1, you had the context right there to easily make the decisions
Fair point. In this instance, the nesting comes from using (for) in a (loop ...) which ends up nesting the results arbitrarily - or rather, in an input dependent, yet useless way.
It would be indeed better not to use flatten-but-x to solve this. OTOH, using for [ ... :let ... :when ... ]
is super terse and expressive.
for example, if you have (for [i (f x)] i)
and (f x)
returns a lists of lists then do (for [i (f x) ii i] ii)
it's more like (defn f [a prefix] (comment omitted termination code)) (for [n (magic a)] (f (drop n a) (conj prefix (first a))))). (magic) returns a small number.
that will concat one level of lists for every recursive call, so in your base case you may need to add a second layer of lists if your lists is meant to be a list of lists
the recursive call chain ends up being exactly the context information you would need to recover in your "flatten, but..."
I followed your instructions and that made it work. I don't understand how or why it works tho
for is a combination of a lot of difference sequence functions, include map and mapcat
(for [x xs y ys] [x y]) => ([x0 y0] [x0 y1] .. [x0 yN] [x1 y0] .. [xN yN])
- cartesian product I believe
any for that doesn't use any of the keyword stuff (:when, :while, etc) can be transformed into an expression of nested mapcats around an inner map, you can do the keyword stuff to you just have to sprinkle in some calls to filter and take-while
(macroexpand '(for [x xs y ys] [x y]))
is significantly harder to grok thank your explanations 🙂
you could do it with either tree-seq (save only colls that don't contain colls) or postwalk (concat any colls that only contain colls)
is there a easy way to make this work :
(ns chapter5)
(defn schedule
"Using the control flow constructs we've learned, write a schedule
function which, given an hour of the day, returns what you'll be
doing at that time. (schedule 18), for me, returns :dinner."
[my-time]
(cond
(<= "0:00" my-time "07.00") :sleeping
(== "07:00" my-time) :breakfast
(<= "07:01" my-time "12:00") :work
(= "12:00" my-time) :lunch
(<= "12:01" my-time "18:00") :more-work
(<= "18:01" my-time "19:00") :dinner
(<= "19:01" my-time "23:59") :watching-tv
))
this is so far the best date-time api i've ever worked with. so if you want to do it right (like how you would do it in a real-world project), i would suggest taking a look at this api.
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/LocalTime.html#parse(java.lang.CharSequence) would be right method to call.
(java.time.LocalTime/parse "07:00")
#object[java.time.LocalTime 0x2b87581 "07:00"]
(str *1)
"07:00"
just as an example, for the first clause in your cond
:
(def midnight (java.time.LocalTime/MIDNIGHT))
#'user/midnight
(def breakfast-time (java.time.LocalTime/parse "07:00"))
#'user/morning
(def my-time (java.time.LocalTime/parse "06:30"))
#'user/my-time
(and (.isAfter my-time midnight)
(.isBefore my-time breakfast-time))
true
oke I was trying another idea but get errors
(ns chapter5)
(defn parse-time
"Parse a string to a time object"
[time-string]
(java.time.LocalTime/parse time-string))
(defn schedule
"Using the control flow constructs we've learned, write a schedule
function which, given an hour of the day, returns what you'll be
doing at that time. (schedule 18), for me, returns :dinner."
[my-time]
(cond
(<= (parse-time "00:00") (parse-time(str my-time)) (parse-time "07:00") ) :sleeping
))
(schedule "03:00")
error :
; Execution error (ClassCastException) at chapter5/schedule (form-init11789170975546566471.clj:9).
; class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')
rule of thumb for when dealing with time: don't roll your own solutions because time is hard. 😉
Right now I only have studied the first 5 chapters of the "Clojure from the ground up " tutorial
I find java time tricky to work with, I think for this particular exercise I’d convert the numeric input to a string
@roelof take a look at the compare
function. For just this limited set of string comparisons, it should be adequate.
isn't compare what <= is using already?
never mind, it only works on numbers
(compare "0:00" "07:00") => 3
you can do two comparisons per case, or if you feel clever do a binary search
right, and using compare twice can tell you if it is
if they are strings
Why not just represent time of day in minutes as a number? No need to introduce string comparisons here
(defn time-as-minutes [hour minute] (+ minute (* 60 hour))
(defn schedule [my-time-in-minutes]
(cond
(<= (time-as-minutes 0 0) my-time-in-minutes (time-as-minutes 7 0)) :sleeping
;; add the rest of the cases
))
for a given pair of times, you'd want the first compare to return positive or zero, and the second compare to return negative or zero
@trailcapital that is also a good idea
If you wanted to use the built-in (jvm) time library, perhaps this might be suitable...
(ns foo
(:import [java.time LocalTime]))
(defn parse
[my-time]
(LocalTime/parse my-time))
(def breakfast (parse "07:00"))
(def midday (parse "12:00"))
(def nearly-dinner (parse "18:00"))
(def dinner (parse "19:00"))
(def late-night (parse "23:59"))
(defn schedule
"Using the control flow constructs we've learned, write a schedule
function which, given an hour of the day, returns what you'll be
doing at that time. (schedule 18), for me, returns :dinner."
[my-time]
(let [my-time' (parse my-time)]
(cond
(.isBefore my-time' breakfast) :sleeping
(= my-time' breakfast) :breakfast
(.isBefore my-time' midday) :work
(= my-time' midday) :lunch
(.isBefore my-time' nearly-dinner) :more-work
(.isBefore my-time' dinner) :dinner
(.isBefore my-time' late-night) :watching-tv)))
(schedule "06:00")
(schedule "07:00")
(schedule "11:00")
(schedule "12:00")
(schedule "15:00")
(schedule "18:00")
(schedule "19:30")
(schedule "00:00")
why do I get this error:
(ns chapter5
(:import [java.time LocalTime]))
(defn parse
[my-time]
(LocalTime/parse my-time))
(def breakfast (parse "07:00"))
(def midday (parse "12:00"))
(def nearly-dinner (parse "18:00"))
(def dinner (parse "19:00"))
(def late-night (parse "23:59"))
(defn schedule
"Using the control flow constructs we've learned, write a schedule
function which, given an hour of the day, returns what you'll be
doing at that time. (schedule 18), for me, returns :dinner."
[my-time]
let [my-time' (parse my-time)]
(cond
(.isBefore my-time' breakfast) :sleeping ))
(schedule "03:00")
error :
unresolved symbol my-time'
Need parens for the let?
now another one :
Could not locate chapter4__init.class, chapter4.clj or chapter4.cljc on classpath.
I feel like you are not the first person here with this same error, wonder if maybe whatever repo you're using is not set up well
but it's saying exactly the problem - you're trying to load chapter4 ns but it's not on your classpath. presumably you have the file so it's something with the config of the classpath
As @alexmiller mentions, this problem shows up now and then. Might be a problematic project template, but also might be a Ux issue with Calva.
this is my repo so far : https://github.com/RoelofWobben/Learning_in_public
your classpath is by default "src" so requiring chapter4
will look for src/chapter4.clj
but that file is located at src/ground_up/chapter4.clj
the namespace needs to be ground-up.chapter4
or the file can be moved out of the ground_up directory to just src
or you can add src/ground_up
onto your classpath and leave the namespaces alone