Fork me on GitHub
#beginners
<
2020-12-12
>
phoenixjj08:12:52

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 ?

dpsutton08:12:39

(let [vowels (set "aeiou")] (count (filter vowels "mississippi")))

🙏 3
metal 3
okwori13:12:12

How do you check the version of Clojure CLI and also upgrade?

borkdude13:12:59

@simon clojure -Sdescribe and clojure --help will print the version

okwori13:12:15

Thanks, I guess an upgrade will be a reinstall, right?

borkdude14:12:11

Depends on your OS. brew upgrade clj-kondo for macOS, linux, might have to reinstall

👍 3
Kevin13:12:38

Any built-in function for this?

(defn repeat-reduce [f acc n]
  (reduce (fn [acc _] (f acc)) acc (range n)))

bronsa13:12:05

check iterate

Kevin13:12:37

Comes close but not entirely what I'm looking for :thinking_face:

Kevin13:12:45

I'd still have to manually take

Kevin13:12:23

take + last or drop + first

Kevin13:12:20

That's actually not bad

roelof16:12:35

Is my question forgotten ??

roelof16:12:06

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))) ?

Aviv Kotek17:12:00

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?

dpsutton17:12:21

What’s the value of (dim-2 [])?

dpsutton17:12:01

So [] is not a valid state but you are starting your atom in that state

dpsutton17:12:14

And it’s rejecting it

dpsutton17:12:39

Did that resolve the confusion?

Aviv Kotek17:12:02

yep, guess I'm misusing atom here

dpsutton17:12:27

What’s your expectation here?

Aviv Kotek17:12:51

basically i'd like to initial a 2dim matrix, something like that: [[1 2 3] ......]

Aviv Kotek17:12:07

(def price-matrix
  ; Item Price Special Price
  [["A" 50 #(* (/ % 3) 130)]
   ["B" 30 #(* (/ % 2) 45)]
   ["C" 20 identity]
   ["D" 15 identity]])

dpsutton17:12:47

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

Aviv Kotek17:12:00

basically i'd like to set each row of the "price-matrix" (cons it) to the initial atom

dpsutton17:12:23

(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?))

dpsutton17:12:48

i'm not following the confusion. maybe update dim-2? to allow for empty vectors as empty 2-dimensional vectors?

Aviv Kotek17:12:50

changing the initial atom to [[]] would work as expected,

dpsutton17:12:03

ok. so make your validator accept that as a valid state

Aviv Kotek17:12:07

so basically i'm good, just need to define the swap! correctly now

roelof18:12:51

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 ?

dpsutton18:12:45

i don't see you using any delay

roelof18:12:52

I did it here : (defn sum [start end] (delay (reduce *(range start end)))

roelof18:12:04

or do I use it on the wrong place ?

roelof18:12:31

I use it after the arguments

dpsutton18:12:08

i don't know. it wasn't in the lsat snippet

roelof18:12:08

chips, you are right. im sorry

roelof18:12:19

but did I use it right ?

dpsutton18:12:56

Now there’s multiplication instead of addition in your sum

dpsutton18:12:03

But looks fine otherwise

roelof18:12:21

🙂 the Clojure from the ground up is vrey fast becomimng very diffuclt

roelof18:12:36

and I want to be sure I understand it well

roelof18:12:04

IM now at a chapter about atoms, delay, promises and futures

roelof18:12:10

so bvery confusing

roelof18:12:22

so sorry to ask so many question

dpsutton18:12:41

Take your time and run the examples and think them through

roelof18:12:27

yesterday I was struggeling with futures

roelof18:12:46

ClojureFarm says you can learn clojure, reframe and databses in 35 days but I think its'too fast

roelof18:12:49

so I take my time

roelof18:12:32

to understand things and try to solve the challenges from this page : https://aphyr.com/posts/306-clojure-from-the-ground-up-state

roelof18:12:38

they look difficult

st3fan19:12:49

What is Clojure Farm 🐮 🐷

roelof19:12:13

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))

borkdude19:12:18

You are not calling the function sum but you are trying to deref the function itself.

roelof19:12:41

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

seancorfield19:12:11

later is not a function there.

roelof19:12:12

@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.

seancorfield19:12:31

(time (deref (sum 0 1e7)))

seancorfield19:12:55

Or something like

(def later (sum 0 1e7))
(time (deref later))

roelof19:12:55

clj::ground_up.chapter6=> 
"Elapsed time: 835.0006 msecs"
49999995000000

seancorfield19:12:56

Your sum is a function that returns a delayed expression

roelof19:12:19

it takes less then 1 second on my computer but its allright

roelof19:12:54

he, a second time costs more time

roelof19:12:00

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.

roelof19:12:32

I think I have to think well how to future macro should look like

seancorfield19:12:54

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=>

roelof19:12:41

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"

roelof19:12:15

so I think you have a faster pc then me 🙂

seancorfield19:12:31

A Microsoft Surface 3 laptop 🙂

roelof19:12:49

I have a pc with 8G and a i5 processor

roelof19:12:00

with Windows 10 Pro

roelof19:12:04

GN all and tomorrow a nice challenge where I already said I have to think how the future macro should look like

roelof20:12:49

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)))

phronmophobic20:12:52

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

dpsutton20:12:16

@U0EGWJE3E how would you go about diagnosing this error? What is the error telling you?

roelof20:12:57

oke, so to get tje answer :

(deref(future* 0 100) 

roelof20:12:45

The error is telling me I have that the future has only 1 argument and I give more @dpsutton

phronmophobic20:12:52

you can also use macroexpand-1 similarly:

repl> (macroexpand-1 '(future 0 100))
;; (reduce + (range start end))

dpsutton20:12:06

no its telling you that the wrong number of args (1) was passed to future

dpsutton20:12:16

how many args does future expect here? how many did you pass it?

roelof20:12:37

i gave 1 and it needed 2

roelof20:12:23

so I have to think well how I can pass the function

dpsutton20:12:45

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

roelof20:12:01

I mean the same

roelof20:12:57

and what I mean is how to pass this promise

(defn sum2 [start end] promise)
in the macro

roelof21:12:01

if I do :

(defn sum2 [start end] promise)

(defmacro future[start end]
  '(reduce + (range start end))
  )

(def answer (future 0 1e7))

dpsutton21:12:05

that promise there is just the function promise

dpsutton21:12:19

its not invoked or used, and doesn't use the start and end supplied

roelof21:12:06

back to the drawing board

roelof21:12:28

The page were promise is explained did not give a example with arguments

roelof21:12:00

stupid to ask for something that is never explained

roelof21:12:02

or do I have to use this : (deliver box :live-scorpions!)

roelof21:12:12

(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*

phronmophobic21:12:54

i kind of agree that their explanation is confusing

phronmophobic21:12:29

I would split up the task into two parts: 1. write a non macro version 2. write the macro

roelof21:12:57

(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

roelof21:12:02

that is I think easy

(defn sum2 [start end] promise)

(defn future*[start end]
  '(reduce + (range start end))
  )

(def calc (future* 0 1e7)

roelof21:12:22

but still I do not see how I can use the promise here

phronmophobic21:12:49

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

phronmophobic21:12:35

you create a promise with (promise) and then you can set its value in any thread using deliver

phronmophobic21:12:21

in my example, I'm simply setting the value of my-promise to 42 with (deliver my-promise 42)

roelof21:12:48

so this schould working

roelof21:12:55

(defn sum2 promise)

(defn future*[start end]
  deliver sum2 0 1e7)

roelof21:12:16

but where do I then set the formula for calculating

roelof21:12:40

so this one

(defn sum [start end] (delay (reduce + (range start end))))

phronmophobic21:12:37

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

phronmophobic21:12:16

can you outline what future's desired behavior is?

roelof21:12:29

as far as I understand a future does something and returns direct the result

roelof21:12:29

so for example

(dotimes [i 5] (future (prn i)))

roelof21:12:15

prints the numbers 1 till 5 but no garuntees that is will print 1 2 3 4 5

roelof21:12:23

it can be in any order

roelof21:12:27

I hope I said it right,this stuff is still confusing for me

phronmophobic21:12:30

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/@

phronmophobic21:12:18

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

roelof21:12:31

yep, so here a future with hopefully all the numbers 1 till 5 in my example

roelof21:12:45

amd with deref I can see the result

phronmophobic21:12:55

in clojure @, will deref the result

roelof21:12:23

oke, I use (deref ...) for it

phronmophobic21:12:34

deref also works

phronmophobic21:12:51

I'm not sure what your current code looks like, but I didn't see where you started a new thread

roelof21:12:24

I have now this :

(def sum2 promise)

(defn future*[start end]
  deliver sum2 0 1e7)

phronmophobic21:12:56

ah ok. promise should probably be something like (promise)

roelof21:12:09

and wonder where this formula must be placed

(reduce + (range start end))

phronmophobic21:12:12

promise is a function that must be called to create a new promise

roelof21:12:02

now I miss you

phronmophobic21:12:12

ie. promise vs (promise)

roelof21:12:36

oke, I changed it to (promise)

phronmophobic21:12:37

(def sum2 promise) vs (def sum2 (promise))

roelof21:12:02

I have now this :

(def sum2 (promise))

(defn future*[start end]
  deliver sum2 0 1e7)

roelof21:12:34

but still I do not see where the reduce miust be placed

phronmophobic21:12:46

what does deliver do?

roelof21:12:02

it placed the two values in the promise

roelof21:12:13

as far as I undestand it

phronmophobic21:12:28

clojure.core/deliver
 [promise val]
Added in 1.1
  Delivers the supplied value to the promise,...

seancorfield21:12:54

@U0EGWJE3E You need to pay more attention to parens. You are not calling deliver because you have no parens around it.

phronmophobic21:12:06

deliver accepts two arguments, the promise and a single value

roelof21:12:00

oke, changed the code to this :

(def sum2 (promise))

(defn future*[start end]
  (deliver sum2 0 1e7))

seancorfield21:12:15

No, deliver takes two arguments.

seancorfield21:12:21

You gave it three.

roelof21:12:38

yep, I was just wanted to say that the code is wrong

roelof21:12:25

(defn future*[start end]
  (deliver sum2 0 )
  (deliver sum2 1e7)
  )

seancorfield21:12:42

No, you can only deliver a single value.

roelof21:12:44

Think this is also wrong. I think the 0 is overwritten

roelof21:12:07

hmm, but I need 2 the begin and the end of the range

roelof21:12:54

or I have to give it the (reduce ...) part ?

🎉 3
roelof21:12:56

(def sum2 (promise))

(defn future* [start end]
  (deliver sum2 (reduce + (range start end))))

phronmophobic21:12:43

sweet. does *future now implement all of future’s desired behavior?

roelof21:12:17

I think so

seancorfield21:12:35

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=>

roelof21:12:44

I only have to find out how to make it work with thr 2 numbers

roelof21:12:22

this is not working `(sum2 0 1e7)

phronmophobic21:12:30

what about the threading requirement?

phronmophobic21:12:38

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

roelof21:12:40

chips you are right

roelof21:12:13

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

seancorfield21:12:26

@U0EGWJE3E 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?

roelof21:12:57

I tried earlier the brave book but that is also going very deep very soon

roelof21:12:39

further no books because I do not want to pay for books just for a hobby

seancorfield21:12:38

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.

seancorfield21:12:32

I learned originally from a course I paid $200 for, and I bought books.

phronmophobic21:12:49

i can’t actually remember how i learned clojure. I didn’t buy any books

roelof21:12:33

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

seancorfield21:12:42

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 🙂

😄 3
roelof21:12:43

which I find pity, I like the language

roelof21:12:17

Again thanks. Time to lseep and think about this

phronmophobic21:12:23

what kind of things would you like to build?

seancorfield21:12:27

@U0EGWJE3E 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...

phronmophobic21:12:49

sometimes there are good resources for specific use cases

roelof21:12:55

I like to solve things like Advent of Code or making websites

phronmophobic21:12:25

there are some really good resources for building web sites

seancorfield21:12:27

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...

roelof21:12:41

Im thinking thenabout a gallery or much later a crm for a volunteer organisation with some member , invoice part

seancorfield21:12:08

@U7RJTCH6J web sites? What sort of resources? I can't imagine anything being suitable given the conversation thread above...

roelof21:12:28

@seancorfield that is why I said I have to think bout how and if I want to go on learning clojure

phronmophobic21:12:45

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

roelof21:12:01

but maybe go back to haskell or try a new language like rust

roelof21:12:18

really going to bed

roelof21:12:36

again thanks but for now byee

seancorfield21:12:47

I think Haskell is much, much harder than Clojure...

seancorfield21:12:00

And Rust is also much, much harder than Clojure.

roelof22:12:40

sorry I do not agree on haskell

roelof22:12:03

I find clojure much harder then haskell

caumond21:12:08

Hi guys, I want to try hexagonal architecture. I don't find good reference for that. How am I suppose to ?

caumond21:12:09

Maybe another way to ask is "how do you implement port / adapter pattern in clojure?"

seancorfield21:12:46

@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.

seancorfield21:12:27

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).

seancorfield21:12:33

@caumond you might find this interesting https://polylith.gitbook.io/polylith/ as a way to have some formal structure between components and layers.

caumond22:12:30

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

chepprey22:12:26

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$ 

seancorfield22:12:10

@chepprey You have an old version of the CLI installed. Upgrade to the latest.

seancorfield22:12:27

See clojure -Sdescribe to see what you've got installed.

chepprey22:12:55

{:version "1.10.1.536"...

seancorfield22:12:24

1.10.1.536 is old -- it doesn't have -X.

✔️ 3
chepprey22:12:40

I shall upgrade, thanks!

seancorfield22:12:48

(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 )

chepprey22:12:32

upgraded to {:version "1.10.1.754" and it works a treat. thanks

Stuart22:12:34

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 ?

seancorfield22:12:43

@qmstuart Like this:

user=> (let [{[x y] :waypoint} {:waypoint [10 1]}] (println 'x x 'y y))
x 10 y 1

seancorfield22:12:30

You can use that destructuring in the function argument instead. let was just easier in the REPL.

Stuart22:12:40

thank you!

Stuart22:12:58

btw, is your talk on repl driven development going to be available on youtube or elsewhere afterwards?

seancorfield22:12:24

After the London event, yes, both versions will be posted online.

Stuart22:12:32

great! 🙂

seancorfield22:12:57

I figure with the two very different timezones, more folks can be there "live".