To count the number of vowels in string. This is the first version.
(defn count-vowels [input]
(let [vowels [\a \e \i \o \u]]
(->>
(for [x (char-array (clojure.string/lower-case input))]
(some #{x} vowels))
(filter some?)
(count))))
Can it be done better ?(let [vowels (set "aeiou")] (count (filter vowels "mississippi")))
What do you experts find of this solutions ? https://github.com/RoelofWobben/Learning_in_public/blob/main/ground_up/src/ground_up/chapter5.clj
How do you check the version of Clojure CLI and also upgrade?
@simon clojure -Sdescribe
and clojure --help
will print the version
Any built-in function for this?
(defn repeat-reduce [f acc n]
(reduce (fn [acc _] (f acc)) acc (range n)))
check iterate
Thanks, I guess an upgrade will be a reinstall, right?
Comes close but not entirely what I'm looking for :thinking_face:
I'd still have to manually take
take + last or drop + first
or nth
That's actually not bad
Thanks
Depends on your OS. brew upgrade clj-kondo for macOS, linux, might have to reinstall
Is my question forgotten ??
user=> (defn sum [start end] (reduce + (range start end)))
user=> (time (sum 0 1e7))
"Elapsed time: 1001.295323 msecs"
49999995000000
Use delay to compute this sum lazily; show that it takes no time to return the delay, but roughly 1 second to deref.
So the answer will be (defn sum [start end] (delay (reduce *(range start end)))
?i'm failing to initial an atom using a validator,
(defn shape [M] .....impl.....)
(defn dim-2? [M]
(= (count (shape M)) 2))
(def price-matrix (atom [] :validator dim-2?))
(defn set-pricing-rules! [M]
(swap! price-matrix into M))
=> Syntax error (IllegalStateException) compiling at (kata01.clj:15:19).
Invalid reference state
but when changing to another validator, i.e: vector?
it compiles, how could it make sense?What’s the value of (dim-2 [])?
false
So [] is not a valid state but you are starting your atom in that state
And it’s rejecting it
yep
right!
Did that resolve the confusion?
yep, guess I'm misusing atom here
What’s your expectation here?
basically i'd like to initial a 2dim matrix,
something like that:
[[1 2 3]
......]
(def price-matrix
; Item Price Special Price
[["A" 50 #(* (/ % 3) 130)]
["B" 30 #(* (/ % 2) 45)]
["C" 20 identity]
["D" 15 identity]])
do that then. (atom [] :validator dim-2?)
is saying start an atom and reject values which don't conform to dim-2?
. And the initial value you give it []
does not conform to the validator function
yea
basically i'd like to set each row of the "price-matrix" (cons it) to the initial atom
(def price-matrix
;; Item Price Special Price
(atom [["A" 50 #(* (/ % 3) 130)]
["B" 30 #(* (/ % 2) 45)]
["C" 20 identity]
["D" 15 identity]]
:validator dim-2?))
i'm not following the confusion. maybe update dim-2? to allow for empty vectors as empty 2-dimensional vectors?
changing the initial atom to [[]] would work as expected,
ok. so make your validator accept that as a valid state
so basically i'm good, just need to define the swap! correctly now
cool!
: ) ty
ser=> (defn sum [start end] (reduce + (range start end)))
user=> (time (sum 0 1e7))
"Elapsed time: 1001.295323 msecs"
49999995000000
Use delay to compute this sum lazily; show that it takes no time to return the delay, but roughly 1 second to deref.
So the answer will be (defn sum [start end] (delay (reduce *(range start end)))
?
Wanted to be sure I understand state well on clojure ?i don't see you using any delay
I did it here : (defn sum [start end] (delay (reduce *(range start end)))
or do I use it on the wrong place ?
I use it after the arguments
i don't know. it wasn't in the lsat snippet
chips, you are right. im sorry
but did I use it right ?
Now there’s multiplication instead of addition in your sum
But looks fine otherwise
🙂 the Clojure from the ground up is vrey fast becomimng very diffuclt
and I want to be sure I understand it well
IM now at a chapter about atoms, delay, promises and futures
so bvery confusing
so sorry to ask so many question
Take your time and run the examples and think them through
I try
yesterday I was struggeling with futures
ClojureFarm says you can learn clojure, reframe and databses in 35 days but I think its'too fast
so I take my time
to understand things and try to solve the challenges from this page : https://aphyr.com/posts/306-clojure-from-the-ground-up-state
they look difficult
What is Clojure Farm 🐮 🐷
what is wrong here :
; Execution error (ClassCastException) at ground-up.chapter6/eval13962 (form-init13914588690575444785.clj:16).
; class ground_up.chapter6$sum cannot be cast to class java.util.concurrent.Future (ground_up.chapter6$sum is in unnamed module of loader clojure.lang.DynamicClassLoader @58b8d871; java.util.concurrent.Future is in module java.base of loader 'bootstrap')
code :
(defn sum [start end] (delay (reduce + (range start end))))
(sum 0 1e7)
(time(deref sum))
You are not calling the function sum
but you are trying to deref the function itself.
hmm, was looking at this example
user=> (def later (delay (prn "Adding") (+ 1 2)))
#'user/later
user=> later
#<Delay@2dd31aac: :pending>
user=> (deref later)
"Adding"
3
later
is not a function there.
@borkdude what is then the right way to tell how long the calculating of the sum takes as the challenge ask me to do
; Use delay to compute this sum lazily; show that it takes no time to return the
; delay, but roughly 1 second to deref.
(time (deref (sum 0 1e7)))
Or something like
(def later (sum 0 1e7))
(time (deref later))
thanks
clj::ground_up.chapter6=>
"Elapsed time: 835.0006 msecs"
49999995000000
Your sum
is a function that returns a delayed expression
it takes less then 1 second on my computer but its allright
he, a second time costs more time
tomorrow or Monday time for this one :
We can do the computation in a new thread directly, using (.start (Thread. (fn [] (sum 0 1e7)))–but this simply runs the (sum) function and discards the results. Use a promise to hand the result back out of the thread. Use this technique to write your own version of the future macro.
I think I have to think well how to future macro should look like
user=> (defn sum [start end] (delay (reduce + (range start end))))
#'user/sum
user-> (time (sum 0 1e7))
"Elapsed time: 0.2965 msecs"
#object[clojure.lang.Delay 0x847f3e7 {:status :pending, :val nil}]
user=> (time (deref (sum 0 1e7)))
"Elapsed time: 156.6201 msecs"
49999995000000
user=>
I see these numbers
clj::ground_up.chapter6=>
"Elapsed time: 0.0385 msecs"
#<Delay@1c7ac1a6: :not-delivered>
clj::ground_up.chapter6=>
"Elapsed time: 848.3458 msecs"
so I think you have a faster pc then me 🙂
A Microsoft Surface 3 laptop 🙂
I have a pc with 8G and a i5 processor
with Windows 10 Pro
GN all and tomorrow a nice challenge where I already said I have to think how the future macro should look like
How to solve this one error: ; Wrong number of args (1) passed to: ground-up.chapter6/future code:
; We can do the computation in a new thread directly, using (.start (Thread.
; (fn [] (sum 0 1e7)))–but this simply runs the (sum) function and discards the
; results. Use a promise to hand the result back out of the thread. Use this
; technique to write your own version of the future macro.
(defn sum2 [start end] promise)
(defmacro future[start end]
'(reduce + (range start end))
)
(def answer (future (sum2 0 1e7)))
one macro writing trick is to put all the logic in a regular function. the regular function makes it easier to test:
(defn sum2 [start end] promise)
(defn future* [start end]
'(reduce + (range start end)))
(defmacro future[start end]
(future* start end))
repl> (future* 0 100)
;; (reduce + (range start end))
you can see that start
and end
are being used literally, instead of as variables@roelof how would you go about diagnosing this error? What is the error telling you?
oke, so to get tje answer :
(deref(future* 0 100)
?
The error is telling me I have that the future has only 1 argument and I give more @dpsutton
you can also use macroexpand-1
similarly:
repl> (macroexpand-1 '(future 0 100))
;; (reduce + (range start end))
no its telling you that the wrong number of args (1) was passed to future
how many args does future expect here? how many did you pass it?
i gave 1 and it needed 2
so I have to think well how I can pass the function
i'm not sure what that means. you defined future as requiring two arguments and then supplied it with only one. the error said "wrong number of args (1) passed to future
I mean the same
and what I mean is how to pass this promise
(defn sum2 [start end] promise)
in the macroif I do :
(defn sum2 [start end] promise)
(defmacro future[start end]
'(reduce + (range start end))
)
(def answer (future 0 1e7))
that promise there is just the function promise
its not invoked or used, and doesn't use the start and end supplied
back to the drawing board
The page were promise is explained did not give a example with arguments
see this page : https://aphyr.com/posts/306-clojure-from-the-ground-up-state
stupid to ask for something that is never explained
or do I have to use this : (deliver box :live-scorpions!)
nope
(defn sum2 [start end] promise)
(defmacro future*[start end]
'(reduce + (range start end))
)
(def calc (deliver sum2 future*))
errror :
`
; Can't take value of a macro: #'ground_up.chapter6/future*
i kind of agree that their explanation is confusing
I would split up the task into two parts: 1. write a non macro version 2. write the macro
(defn sum2 [start end] promise)
(defmacro future*[start end]
'(reduce + (range start end))
)
(def calc (deliver sum2 (future 0 1e7)))
error:
; Unable to resolve symbol: start in this context
yep
that is I think easy
(defn sum2 [start end] promise)
(defn future*[start end]
'(reduce + (range start end))
)
(def calc (future* 0 1e7)
but still I do not see how I can use the promise
here
here's an example of how to use promise since it doesn't seem to be explained:
;; promise example
;;
;; create a promise
> (def my-promise (promise))
;; start a new thread
;; the new thread will set the value of my-promise to 42
> (.start (Thread. (fn []
(deliver my-promise 42))))
;; nil
;; access the value of my-promise
;; this will block the dereferencing thread until a value is
;; delivered to my-promise
> @my-promise
;; 42
Hi guys, I want to try hexagonal architecture. I don't find good reference for that. How am I suppose to ?
you create a promise with (promise)
and then you can set its value in any thread using deliver
in my example, I'm simply setting the value of my-promise
to 42 with (deliver my-promise 42)
hmm
so this schould working
(defn sum2 promise)
(defn future*[start end]
deliver sum2 0 1e7)
Maybe another way to ask is "how do you implement port / adapter pattern in clojure?"
but where do I then set the formula for calculating
so this one
(defn sum [start end] (delay (reduce + (range start end))))
the goal is to recreate the behavior of future
. i'm not sure the provided explanation of what future
does is explained clearly. maybe it's worth breaking down what future
's behavior is
can you outline what future
's desired behavior is?
as far as I understand a future does something and returns direct the result
so for example
(dotimes [i 5] (future (prn i)))
prints the numbers 1 till 5 but no garuntees that is will print 1 2 3 4 5
it can be in any order
ah ok
@caumond It's mostly just about layers and making sure the dependencies only go in one direction. In Clojure you mostly want to have a pure functional core and have your side-effect-y stuff at the edges.
I hope I said it right,this stuff is still confusing for me
from future
's doc string:
Takes a body of expressions and yields a future object that will
invoke the body in another thread, and will cache the result and
return it on all subsequent calls to deref/@
so crucially: 1. it does the work in a separate thread 2. it doesn't directly return the value, it returns an object that can be dereferenced to obtain the value
Some folks will suggest using protocols to mirror interfaces but I don't think that's necessarily a good way to go (if you only have one implementation of a protocol, you might just as well use plain functions).
yep, so here a future with hopefully all the numbers 1 till 5 in my example
amd with deref I can see the result
in clojure @
, will deref the result
oke, I use (deref ...)
for it
yup
deref
also works
I'm not sure what your current code looks like, but I didn't see where you started a new thread
I have now this :
(def sum2 promise)
(defn future*[start end]
deliver sum2 0 1e7)
ah ok. promise
should probably be something like (promise)
and wonder where this formula must be placed
(reduce + (range start end))
promise
is a function that must be called to create a new promise
@caumond you might find this interesting https://polylith.gitbook.io/polylith/ as a way to have some formal structure between components and layers.
??
now I miss you
ie. promise
vs (promise)
oke, I changed it to (promise)
(def sum2 promise)
vs (def sum2 (promise))
I have now this :
(def sum2 (promise))
(defn future*[start end]
deliver sum2 0 1e7)
but still I do not see where the reduce miust be placed
what does deliver
do?
it placed the two values in the promise
as far as I undestand it
clojure.core/deliver
[promise val]
Added in 1.1
Delivers the supplied value to the promise,...
@roelof You need to pay more attention to parens. You are not calling deliver
because you have no parens around it.
deliver
accepts two arguments, the promise and a single value
oke, changed the code to this :
(def sum2 (promise))
(defn future*[start end]
(deliver sum2 0 1e7))
No, deliver
takes two arguments.
You gave it three.
yep, I was just wanted to say that the code is wrong
(defn future*[start end]
(deliver sum2 0 )
(deliver sum2 1e7)
)
No, you can only deliver a single value.
Think this is also wrong. I think the 0 is overwritten
hmm, but I need 2 the begin and the end of the range
or I have to give it the (reduce ...)
part ?
(def sum2 (promise))
(defn future* [start end]
(deliver sum2 (reduce + (range start end))))
sweet. does *future now implement all of future’s desired behavior?
I think so
are you sure?
You can try this stuff out in the REPL piece by piece:
user=> (def p (promise))
#'user/p
user=> (deliver p 0)
#object[clojure.core$promise$reify__8501 0x220c9a63 {:status :ready, :val 0}]
user=> (deliver p 1e7)
nil
user=> @p
0
user=>
I only have to find out how to make it work with thr 2 numbers
this is not working `(sum2 0 1e7)
what about the threading requirement?
also, i’m pretty confident in recommending that you find a different tutorial to work through. unfortunately, i’m not sure what a good getting started tutorial might be
chips you are right
yep, the course im now doing is telling met that doing the clojur from the ground up is a good starting point. But I see that on almost every challenge I need help to solve the challenges
@roelof You've been trying to learn Clojure on and off for a long time now. Remind me which books you've tried to work through?
I tried earlier the brave book but that is also going very deep very soon
further no books because I do not want to pay for books just for a hobby
Well, then you are very restricted on material: "Brave and True" and "Ground Up" are pretty much the only free ones I know out there.
bummer
I learned originally from a course I paid $200 for, and I bought books.
i can’t actually remember how i learned clojure. I didn’t buy any books
oke,, Thanks both so far for the help. Time to think about how to go on on my clojure way or know that clojure is not for me
My first two were Joy of Clojure and Clojure in Action. Then I bought Clojure Programming. Since then I've bought almost every single Clojure book out there 🙂
which I find pity, I like the language
Again thanks. Time to lseep and think about this
what kind of things would you like to build?
@roelof Given how you've struggled with the basics of Clojure each time you've tried, it is possible that Clojure may not be your thing...
sometimes there are good resources for specific use cases
I like to solve things like Advent of Code or making websites
there are some really good resources for building web sites
I was just talking with someone who was trying to learn Forth and finding that they just couldn't "get it" when they actually tried to build stuff, even though they'd read books and liked the idea of the language...
Im thinking thenabout a gallery or much later a crm for a volunteer organisation with some member , invoice part
@smith.adriane web sites? What sort of resources? I can't imagine anything being suitable given the conversation thread above...
@seancorfield that is why I said I have to think bout how and if I want to go on learning clojure
it’s not clojure, but i’ve heard good things about the “learn X the hard way” series, https://shop.learncodethehardway.org I think their ruby edition is freely available
but maybe go back to haskell or try a new language like rust
really going to bed
again thanks but for now byee
I think Haskell is much, much harder than Clojure...
And Rust is also much, much harder than Clojure.
ok, pure functional seems more appealing, I didn't know polylith but I'll try to do the simple way, with layers and their dependency well managed
thx @seancorfield
Hi - I'm going through https://clojure.org/guides/deps_and_cli to try out deps.edn, I've gone literally through the steps in the "Writing a program" section. It's just a "hello world" world program that also prints the current timestamp. I'm getting this error instead:
:~/hello-world$ clj -X hello/run
Execution error (FileNotFoundException) at java.io.FileInputStream/open0 (FileInputStream.java:-2).
-X (No such file or directory)
Full report at:
/tmp/clojure-6673920467411785967.edn
:~/hello-world$
@chepprey You have an old version of the CLI installed. Upgrade to the latest.
See clojure -Sdescribe
to see what you've got installed.
{:version "1.10.1.536"...
1.10.1.536 is old -- it doesn't have -X
.
I shall upgrade, thanks!
(I'm on 1.10.1.763 but that's a prerelease -- 1.10.1.754 is the latest, see https://clojure.org/releases/tools )
sorry I do not agree on haskell
I find clojure much harder then haskell
upgraded to {:version "1.10.1.754"
and it works a treat. :thanks:
I have a map like this
{:ship [0 0] :waypoint [10 1]}
I pass it to a function and destructure it
(defn move2 [{:keys [ship waypoint] :as acc} [inst distance]]
(let [[waypoint-x waypoint-y] waypoint]
;; do stuff.
))
Can I destructure the keys and waypoint-x
and waypoint-y
in the argument destructuring, rather than destructuring int he arg list AND the let ?@qmstuart Like this:
user=> (let [{[x y] :waypoint} {:waypoint [10 1]}] (println 'x x 'y y))
x 10 y 1
You can use that destructuring in the function argument instead. let
was just easier in the REPL.
thank you!
btw, is your talk on repl driven development going to be available on youtube or elsewhere afterwards?
After the London event, yes, both versions will be posted online.
great! 🙂
I figure with the two very different timezones, more folks can be there "live".