Fork me on GitHub
#beginners
<
2021-01-10
>
popeye08:01:33

(fn-name input-string [7 9 13] [25 26 29]) i am writing function where i am planning to apply substring of for each values of vactor example (sub input-string 7 25) (sub input-string 9 26) (sub input-string 13 29) How can I do it in clojure?

NPException08:01:24

One way to do this would be to use map. It takes a mapping function and any number of collections. The mapping function needs to take as many parameters as there are collections passed to map .

NPException08:01:12

The mapping function will then receive the first element of each collection as the its first set of arguments, then the second elements as the second set of arguments and so on.

NPException08:01:33

So this

(map f [1 3] [2 4])
is roughly equivalent to
[(f 1 2)
 (f 3 4)]

NPException08:01:56

Does this help you?

popeye08:01:23

i will try on my code and let you know 🙂

popeye13:01:09

I tried with map and that helped 🙂 sorru for late reply, wanted to complete the functionality

roelof10:01:24

hmm, what did I not understood here :

; Use the list function, quoting, and read-string to create a list that, when 
; evaluated, prints your first name and your favorite sci-fi movie.

(list '(read-string str) "Roelof Wobben, Star Wars")

(eval  (list '(read-string str) "Roelof Wobben, Star Wars") )
error:
; Execution error (ClassCastException) at chapter7/eval16506 (form-init11571273748977578313.clj:9).
; class clojure.core$str cannot be cast to class java.lang.String (clojure.core$str is in unnamed module of loader 'app'; java.lang.String is in module java.base of loader 'bootstrap')

NPException10:01:24

'(read-string str) results in a list of the symbols read-string and str . When evaluated, it results in a function call to read-str with whatever is bound to str as its argument. So it's passing the function str into read-str .

roelof10:01:42

oke, but this was also not right I think : (list '(read-string "my-text"))

NPException10:01:31

The task is effectively to create a list of the symbol read-string and your text. (list '(read-string "my-text")) would result in the list: ((read-string "my-text")) , since you are quoting the list (read-string "my-text") already.

NPException10:01:48

You only need to quote read-string .

NPException10:01:18

So what it's asking for is this: (list 'read-string "my-text")

NPException10:01:15

Getting used to quoting can take a while 🙂

roelof10:01:29

yep and figure out when something needs to be surrounded by parentheses also 😞

roelof10:01:54

Am I right that only "Roelof" is printed here

(list 'read-string "Roelof Wobben, Star Wars")

(eval (list 'read-string "Roelof Wobben, Star Wars"))

NPException11:01:06

oh, sorry I think I misunderstood the task a bit. So the list we now create is this: (read-string "Roelof Wobben, Star Wars") But read-string will only read the first form from a given string, which in this case will by the symbol Roelof . Is there a more detailed description to the task or any previous tasks that this one builds on top?

roelof11:01:39

not that I know

roelof11:01:15

but this is the page everything is explained : https://www.braveclojure.com/read-and-eval/

NPException11:01:34

Ah, braveclojure! I learned the language from there about 3 years ago. 🙂 Maybe I have my exercise code still lying around somewhere

roelof11:01:53

I use it now for some 2 weeks to learn clojure but for every challenge I needed some help. Very frustating

NPException11:01:51

Looking at the examples in that chapter, the exercise is just to get your familiar with those functions and concepts by combining them in some ways. One of my solutions was this:

(eval (read-string "(list 'Dirk 'Interstellar)"))

NPException11:01:22

Don't beat yourself up if you don't get it right away. Especially all the macro related stuff can take some time. I also do remember that I found the second exercise in that chapter very tricky, so I skipped it at first and came back to it later.

roelof11:01:03

yep, that prints out a list with the two data

roelof11:01:14

yep, I know

roelof11:01:39

I did try to make it and got the wrong answer

roelof11:01:30

I thought this was equal (1 + 3 * 4 - 5) and (- (* 4 (+ 1 3)) 5) but it is not

roelof11:01:42

and this one is given me the right output : (- (+ (* 4 3) 1) 5)

roelof11:01:09

so with the knowlegde that I have I never can make a general solution

NPException11:01:48

(- (* 4 (+ 1 3)) 5) does not equal (1 + 3 * 4 - 5) , * needs to take precedence over + .

roelof11:01:52

yep, as I said I noticed

NPException11:01:30

I can give you a link to my solution for the second exercise, if you want something to compare against.

roelof11:01:58

Thanks, But first I will try it on my own

👍 3
roelof11:01:31

I think I have to start over again

roelof11:01:45

make things to complicated

(defn infix [expr]
  (let [splitted (str/split (subs expr 1 (- (count expr) 1)) #" ")]
    ))

NPException11:01:10

do you take the expression as a string?

NPException11:01:01

try passing it as a list instead by just quoting it: (infix '(1 + 3 * 4 - 5)) That way you can use all of Clojure's data manipulation functions directly.

roelof11:01:11

yep, that was my idea and then split it on the space and delete the parentheses

roelof11:01:09

hmm, almost there I hope

(defn infix [expr]
   (let [first (first expr)
         second( nth expr 3)
         thirth (nth expr 5)
         fourth (nth expr 7)
         fifth (nth expr 9)
         sixth (nth expr 11)
         seventh (nth expr 13)]
     (list sixth(list second) )
     ))

(infix "(1 + 3 * 4 - 5)")
but that gives :
(\- (\+))

NPException11:01:03

as expected. You are creating a list, consisting of the sixth element, and a nested list with the second element.

NPException11:01:33

second element is + , sixth is -

roelof11:01:54

I think I got it :

(defn infix [expr]
   (let [first (first expr)
         second( nth expr 3)
         thirth (nth expr 5)
         fourth (nth expr 7)
         fifth (nth expr 9)
         sixth (nth expr 11)
         seventh (nth expr 13)]
     (list (read-string (str sixth)) (list (read-string (str second)) 2 3)1)
     ))
this gives the right answer

roelof11:01:13

I only have to adapt it to the whole formula

NPException11:01:55

are you still passing expr as a string?

roelof11:01:19

yep (eval (infix "(1 + 3 * 4 - 5)") )

NPException11:01:06

do (eval (infix '(1 + 3 * 4 - 5))) instead, then you can omit your read-string and str calls

NPException11:01:33

you need to adjust your nth indices then, too.

roelof11:01:08

yep, I see

roelof11:01:20

I know get a out of bounds error

NPException11:01:47

I assume your indices are off by 1 now.

roelof11:01:42

Still a out of bounds error

NPException11:01:47

can you paste your current code ?

roelof11:01:49

(defn infix [expr]
   (let [first (first expr)
         second( nth expr 2)
         thirth (nth expr 3)
         fourth (nth expr 4)
         fifth (nth expr 5)
         sixth (nth expr 6)
         seventh (nth expr 7)]
     (list (sixth  (list (second 2 3) )))))


(infix '(1 + 3 * 4 - 5))

NPException11:01:26

off by 1. indices start at 0, so your second element will be at index 1 and so on.

roelof11:01:07

still not well

(defn infix [expr]
   (let [first (first expr)
         second( nth expr 1)
         thirth (nth expr 2)
         fourth (nth expr 3)
         fifth (nth expr 4)
         sixth (nth expr 5)
         seventh (nth expr 6)]
     (list (sixth  (list (second 2 3) )))))



(eval (infix '(1 + 3 * 4 - 5)) )

roelof11:01:20

; Syntax error (IllegalArgumentException) compiling at (chapter7.clj:28:1).
; Can't call nil, form: (nil)

NPException11:01:36

which line is line 28?

roelof11:01:54

the eval line

NPException12:01:12

(list (sixth  (list (second 2 3) )))
That part needs fixing. sixth and second are now bound to the symbols - and + . Calling a symbol as function here will just return nil, so the list you return from infix ends up being (nil) , which when eval'd results in that error.

NPException12:01:23

You want to construct lists with those symbols as the first element instead, so don't nest them in a function call

(list sixth (list second 2 3))

roelof12:01:57

This works :

(defn infix [expr]
  (let [first (first expr)
        second (nth expr 1)
        thirth (nth expr 2)
        fourth (nth expr 3)
        fifth (nth expr 4)
        sixth (nth expr 5)
        seventh (nth expr 6)]
    (list sixth (list second (list fourth thirth fifth) first) seventh)))

NPException12:01:28

Now next step would be to make it work for other formulas, like (3 * 2 - 1) and others

roelof12:01:05

I do not know if I can make that work

roelof12:01:20

then you have to make something that looks for a order

NPException12:01:57

yes. I made a function which takes two operators, and returns true if the first one takes precedence over the second. To determine that, I put priority values in a map (one for each of the basic operators + - * / ) and then looked up the values for both operators in the map. If the value for the first operator is higher than the second, I returned true.

NPException12:01:54

This was my priority map, just to give you an idea: (def priorities {'+ 1, '- 1, '* 2, '/ 2})

NPException12:01:04

To make your life easier, you can try to implement your infix function only for lists of exactly 5 elements first. (e.g (infix '(a op1 b op2 c)) ) That way you only have to worry about 2 operators for now.

roelof13:01:32

this is I think a nice lesson

roelof13:01:53

may I choose what op1 and op2 are

roelof13:01:09

and maybe use a regex to split it into pieces ?/

roelof13:01:01

(defn infix2 [expr]
  (let [splitted (re-matches #"((d+) (.) (d+) (.) (d+))" expr)]
    splitted))



(infix2 '(10 + 2 * 3))
error:
; Execution error (ClassCastException) at chapter7/infix2 (form-init6806598393956264445.clj:29).
; class clojure.lang.PersistentList cannot be cast to class java.lang.CharSequence (clojure.lang.PersistentList is in unnamed module of loader 'app'; java.lang.CharSequence is in module java.base of loader 'bootstrap')

NPException14:01:47

you are trying to use strings again

NPException14:01:48

keep in mind that expr is just a list of alternating values and operators.

NPException14:01:23

so no. regex bad. (in this case at least 😄)

NPException14:01:56

Also I'd like to point you at a section in a previous chapter: https://www.braveclojure.com/do-things/#Destructuring

NPException14:01:07

you can destructure your expr in the parameter list of the function for easy access to the elements of it.

roelof14:01:10

yep, I can do that , I did that in my former solution But it is then not a problem when there are more or less parameters

roelof14:01:48

I mean I can do this again :

(let [first (first expr)
        second (nth expr 1)
        thirth (nth expr 2)
        fourth (nth expr 3)
        fifth (nth expr 4)

roelof14:01:25

but what if I do (+ 1 2) or (1+2+3+4+5+6)

roelof14:01:48

then this destructering does not work

NPException15:01:00

It does work, but we can get to it after we made your approach work. 🙂

roelof15:01:57

so I can start with this :

(defn infix [expr]
  (let [first (first expr)
        second (nth expr 1)
        thirth (nth expr 2)
        fourth (nth expr 3)
        fifth (nth expr 4)
        sixth (nth expr 5)
        seventh (nth expr 6)]

roelof15:01:19

and I know that 2 4 6 are the operators

roelof15:01:25

the rest I do not see

NPException15:01:01

Yes, but you need to adjust it. The minimum case for the infix is an expression of 3 elements. For example (1 + 3) . This means that you can't use nth for anything after the third element, since if there is no fourth, it will error with an IndexOutOfBounds.

roelof15:01:49

oke, im curious which way this is going to

NPException15:01:24

So how can you remove the first 3 elements from expr to get a (potentially empty) list of all remaining elements?

NPException15:01:46

If you have a list of remaining elements, you can check if it is empty. If it is, you have the base case and can just return a list of the second, first, and third element.

roelof15:01:04

(drop 3 expr)

roelof15:01:22

we have then this :

(defn infix2 [expr]
  (let [first (first expr)
        second (nth expr 1)
        thirth (nth expr 2)
        r (drop 3 expr)]
  ))

roelof15:01:32

so then a check if r is empty ?

roelof15:01:22

oke we know then that second is the parameter and one and three the numbers

NPException15:01:30

at this point I would suggest to use other names than first and second , because you are hiding the respective clojure core functions by doing that.

roelof15:01:49

so we can do (list second first thirth)

roelof15:01:11

oke , any recoomendations then for a better name ?

roelof15:01:43

maybe a op1 b ?

NPException15:01:17

Yeah. That's what I ended up using too. You can also be more explicit, like first-number, operator , second-number . It's totally up to you in the end, it just should be easy to read and understand when you come back to the code later.

roelof15:01:03

oke, we have this :

(defn infix2 [expr]
  (let [first-number (first expr)
        operator (nth expr 1)
        second-number (nth expr 2)
        r (drop 3 expr)]
    (if (empty? r))
      (list operator first-number second-number)
      
    ))

roelof15:01:41

for the second case we need the priorites variable

roelof15:01:15

there I have to think well

roelof15:01:41

Right now we do not know the second operator

roelof15:01:52

so we cannot compare anything

NPException15:01:03

if r is not empty, where will the second operator be?

NPException15:01:38

more precisely it will be the first element of r.

roelof15:01:20

yep, you are right

NPException15:01:46

Also I just noticed your if does not surround the (list .. below it

roelof15:01:06

oke, then now I have to figure out how I can find the priorities

NPException15:01:15

you have some options to lookup the priorities, where these 2 would be the most commonly used: Call get with the priorities map and an operator or use the priorities map itself as the lookup function.

NPException15:01:38

If I'm giving you too many directions at any point, let me know. I don't want to ruin the learning experience by just pushing a solution onto you 😅

roelof15:01:16

I will say i to you iof you help me too much

roelof15:01:09

so like this :

(defn infix2 [expr]
  (let [first-number (first expr)
        operator (nth expr 1)
        second-number (nth expr 2)
        r (drop 3 expr)]
    (if (empty? r)
      (list operator first-number second-number)
      (if ( < (get priorities operator) (get priorities (first r)))
          "do something"
          "do something else"
        
        
        ))))

roelof15:01:00

now I think I need to work on paper what schould happen now

roelof15:01:09

so I need some moments I think

✔️ 3
roelof16:01:30

he, im i righht here 1 + 2 * 3 will be in clojure (+ ( * 2 3) 1) and 2 * 3 + 1 will also be (+ ( * 2 3) 1) `

roelof16:01:43

so it does not matter

roelof16:01:36

hmm, im still thinkimg I need to join the second-number back to r when r is not empty

NPException16:01:04

partially correct. only if the second operator has a higher priority

roelof16:01:23

hmm, Im stuck

roelof16:01:23

in the first case I would do something like (list operator(list (infix2 r second) first-number)

roelof16:01:52

but that would not work because then the first-number will be the operator and that is not good

NPException16:01:38

let's first deal with the (in my opinion) easier case, which is the second case.

NPException16:01:49

How would you do that?

roelof16:01:54

(infix2 r (operator first-number second-number) `

roelof16:01:22

but that cannot be good because infix2 wants only 1 argument and now there are 2

roelof16:01:05

or I can do (infix2 (list r (operator first-number second-number)

NPException16:01:34

not quite. You need to prepend (operator first-number second-number) to r , and pass that into infix2

NPException16:01:00

sorry I mean (list operator first-number second-number)

roelof16:01:01

oke , so (infix2 (conj r (list operator first-number second-number)) ?

NPException16:01:07

yeah, that should do it

roelof16:01:25

now the second one

roelof16:01:38

we need something like (list operator(list (infix2 r) second-number) first-number)` ?

roelof16:01:01

because we do not have the operator and the other number

NPException16:01:36

let's break it up. What would the nested call to infix2 look like?

roelof16:01:57

im still thinking (infix r second-number)

roelof16:01:30

bcause r has the operator and the number we are missing

NPException16:01:57

yes, but infix2 only takes one argument, so you need to prepend second-number to r

roelof16:01:44

oke so (index (conj r second-number))

NPException16:01:13

infix2 instead of index, but yeah 😄

roelof16:01:40

I want to type faster then i can

roelof16:01:19

so the call will be (list operatotor (list (infix2 (conj r second-number))) first-number)

roelof16:01:40

I hope I did not miss any parentheses

roelof16:01:39

something not right with parentheses here :

(infix2 '(10 + 2 * 3))

(+ ((* 2 3)) 10)

roelof16:01:26

code so far :

(defn infix2 [expr]
  (let [first-number (first expr)
        operator (nth expr 1)
        second-number (nth expr 2)
        r (drop 3 expr)]
    (if (empty? r)
      (list operator first-number second-number)
      (if (< (get priorities operator) (get priorities (first r)))
        (list operator (list (infix2 (conj r second-number))) first-number)
        (infix2 (conj r (list operator first-number second-number)))))))

NPException16:01:30

there are 2 issues here

(list operator (list (infix2 (conj r second-number))) first-number)

NPException16:01:13

1. you don't need to put the nested infix2 in another list

roelof16:01:39

thanks, this seems to work

(defn infix2 [expr]
  (let [first-number (first expr)
        operator (nth expr 1)
        second-number (nth expr 2)
        r (drop 3 expr)]
    (if (empty? r)
      (list operator first-number second-number)
      (if (< (get priorities operator) (get priorities (first r)))
        (list operator (infix2 (conj r second-number)) first-number)
        (infix2 (conj r (list operator first-number second-number)))))))

roelof16:01:11

(infix2 '(10 + 2 * 3))  gives  (+ (* 2 3) 10)

🙌 3
NPException16:01:23

2. first-number should come after operator, not as the last element (it doesn't make a functional difference here, but it would if you want to expand the functionality to work with nested infix expressions like (3 * (1 + 2)))

roelof16:01:44

(infix2 '(2 * 3 + 10)) gives also (+ (* 2 3) 10)

roelof16:01:14

pff, still have the feeling that I have to learn a lot how to approach this sort of problems

roelof16:01:28

and thanks for the patience with me for the whole day

NPException16:01:33

That comes with time and practice

NPException16:01:59

ah, no worries, I was only playing games on my main monitor most of the time 😄

NPException16:01:23

I would like to quickly go back to the topic of destructuring if you have a few more minutes

roelof16:01:19

hmm, one thing im still not happy

NPException16:01:33

sure, what's it?

roelof16:01:58

(infix2 '(10 + 2 * 3)) gives (+ 10 (* 2 3))

NPException16:01:26

which is correct

roelof16:01:31

where (infix2 '(2 * 3 + 10)) gives (+ (* 2 3) 10)

NPException16:01:41

which is also correct

roelof16:01:50

why on the second one is the 10 in the last position

roelof16:01:03

can we not look both the same

roelof16:01:11

or am I overthinking ?

NPException16:01:02

if you imagine replacing 2 * 3 with 6 ->

(10 + 6) -> (+ 10 6)
(6 + 10) -> (+ 6 10)

NPException16:01:14

it's just keeping the order of arguments like they were in the original expression. Which is expected in my opinion.

NPException16:01:41

You don't want it to accidentally re-order the arguments to a division or subtraction.

NPException16:01:37

Now that I think about it, that is the actual important reason for the 2) issue I mentioned earlier. :thinking_face:

roelof17:01:48

and never knew that recursion could solve so many problems

NPException17:01:49

yeah, I never used it much when I was working with Java, but now I use it quite regularly

roelof17:01:21

oke, I know ik from haskelll where it is also used very often

roelof17:01:30

java I do not have learned

roelof17:01:16

pnl;y some haskell., some c# and some ruby

roelof17:01:00

and for practice I do now the brave book and exercism

roelof17:01:23

later on maybe 4 clojure and maybemuch later Advent of Code

NPException17:01:31

That's more than I know. I only know Java and Clojure 😅 So quickly back to destructuring: The infix function breaks expr into 4 parts: the first three elements and the rest after those. Which can be done with destructuring quite easily:

(defn infix2 [[first-number operator second-number & r]]
  (if (empty? r)
    (list operator first-number second-number)
    (if (< (get priorities operator) (get priorities (first r)))
      (list operator first-number (infix2 (conj r second-number)))
      (infix2 (conj r (list operator first-number second-number))))))

roelof17:01:38

oke and it still then works ?

roelof17:01:49

I thougth I need a let to deconstruct

NPException17:01:33

I thought that as well at first, but destructuring works in quite a few places

roelof17:01:34

yep, it does

roelof17:01:13

learned another "trick"

NPException17:01:28

want a small extra challenge? 😄

roelof17:01:03

always. as lomg as I can do it with the knowlegde I get from the book

roelof17:01:21

I only do not know if I got it working today

roelof17:01:29

almost dinner/supper here

NPException17:01:45

I think that should be doable. The challenge would be to make your infix function work with arbitrarily nested expressions. Example

(infix2 '(3 * (2 + (5 - 3) / 2)))
=> (* 3 (+ 2 (/ (- 5 3) 2)))

NPException17:01:24

there is only one spot that needs to be changed

NPException17:01:05

In case the book did not mention it yet: To check if something is a list, you call (list? the-thing)

roelof17:01:55

oke, from the c# time I learned on OOP its not good to ask a object what it is

NPException17:01:37

makes sense in OOP, since you rather use methods and inheritance there. But since we are just juggling data around here, we need to be able to check what kind of data we're dealing with.

roelof17:01:00

just thinking how to to solve this

roelof17:01:13

I see what needs to be changed

; (* 3 (+ 2 (/ (- 5 3) 2))) => current outcome
; (* 3 (2 + (5 - 3) / 2))   => preffered outcome 

roelof17:01:14

thinkingg I might need another if then to solve this

NPException17:01:09

technically correct, but maybe not in the way you think right now. Where would you put that if and what would it check for?

roelof17:01:29

I was thinking just before the if then we have now and it would do a check if first number is a list

NPException17:01:54

why do you want to check it there?

roelof17:01:39

just a feeling what is the right place

NPException17:01:04

now what would you do if the first argument is a list and not a number?

roelof17:01:19

because It think both cases which we have now could hit this problem

roelof17:01:39

then we have a parse that again somehow

roelof17:01:25

What we are making is a parser as far as I see it

roelof17:01:23

am I on the right track or not ?

NPException17:01:31

if an argument is a list, (so a nested expression) we want to turn it into its infix representation.

NPException17:01:54

there's only one place in the function where all arguments are ultimately put into an infix format. At that place, you either put in the argument itself or the infix version of it if it's a list.

roelof17:01:39

I think you mean like here : (list operator first-number second-number)

roelof17:01:06

be back after supper/dinner

roelof17:01:17

I still miss something I think

roelof17:01:32

you want a if then into that part ?

NPException17:01:00

yep exactly. one for each first-number and second-number

roelof18:01:11

so like this :

(list operator (if (list? first-number) ....) (if (list? second-number) ....)

roelof18:01:45

oke, then I have to think how to proceed then

roelof18:01:18

chips, I does not know about match

(defn infix2 [[first-number operator second-number & r]]
  (if (empty? r)
    (list operator (match [(list? first-number) (list? second-number)]
                     [true false] "do something"
                     [false true] "do something else"
                     [true true]  "do another something"))
    (if (< (get priorities operator) (get priorities (first r)))
      (list operator first-number (infix2 (conj r second-number)))
      (infix2 (conj r (list operator first-number second-number))))))

roelof18:01:37

and this is not going to solve it

(ns chapter7
  (:require [clojure.core.match :refer [match]]))

NPException18:01:57

you are thinking to complicated 🙂

NPException18:01:25

match is a cool thing, but definitely not needed here

NPException18:01:36

let's rename first-number to a and second-number to b for now, makes it easier to write about 😄

roelof18:01:23

I had this :

(defn infix2 [[first-number operator second-number & r]]
  (if (empty? r)
    (list operator (if (list? first-number) 
                     (list operator (infix2 firstnumber) second-number)         
                     ) 
          (if (list? second-number) 
            (list operator firstnumber (infix2 second-number))   
            )
    (if (< (get priorities operator) (get priorities (first r)))
      (list operator first-number (infix2 (conj r second-number)))
      (infix2 (conj r (list operator first-number second-number)))))))

roelof18:01:35

but then I need on both cases a else branch

roelof18:01:26

and witth this I get a null pointer exception

(defn infix2 [[first-number operator second-number & r]]
  (if (empty? r)
    (list operator (if (list? first-number) 
                     (list operator (infix2 first-number) second-number)
                      (if (list? second-number)
                        (list operator first-number (infix2 second-number))
                        (list operator first-number second-number)
                        )         
                     ) 
   (if (< (get priorities operator) (get priorities (first r)))
      (list operator first-number (infix2 (conj r second-number)))
      (infix2 (conj r (list operator first-number second-number)))))))

NPException18:01:40

you are already within (list operator ... , you don't need to call that again in the nested ifs. The nested ifs should only return either the number or the infixed nested list.

NPException18:01:29

keep in mind that everything is an expression. Those nested ifs do not directly return from your infix2 function.

roelof18:01:45

(defn infix2 [[first-number operator second-number & r]]
  (if (empty? r)
    (list operator (if (list? first-number)
                     (infix2 first-number)
                     (if (list? second-number)
                       (infix2 second-number)
                       (first-number second-number))))
          (if (< (get priorities operator) (get priorities (first r)))
            (list operator first-number (infix2 (conj r second-number)))
            (infix2 (conj r (list operator first-number second-number))))))

roelof18:01:59

; Execution error (ClassCastException) at chapter7/infix2 (form-init6806598393956264445.clj:34).
; class java.lang.Long cannot be cast to class clojure.lang.IFn (java.lang.Long is in module java.base of loader 'bootstrap'; clojure.lang.IFn is in unnamed module of loader 'app')

NPException18:01:24

you also shouldn't nest the (if (list? second-number) in the check for the first one

NPException18:01:41

instead:

(list operator
      (if (list? first-number)
        (infix2 first-number)
        )
      (if (list? second-number)
        (infix2 second-number)
        ))

roelof18:01:03

so no else on the first if then

NPException18:01:09

both ifs are independent of each other.

roelof18:01:11

I thought that was needed

NPException18:01:16

There is an else needed for both of them

NPException18:01:38

I just don't want to give it to you straight away 🙂

roelof18:01:52

and im nowvery confused

roelof18:01:25

if first-number is not a list then we cannot know if second-number is a list of not

roelof18:01:44

so what schould then be in the else of that one ?

NPException18:01:06

first-number and second-number can be lists or numbers completely independent of each other

NPException18:01:31

(1 + 2) ((1 * 3) + 2) (1 + (5 *2))

NPException18:01:02

in all those cases operator is the + , and first-number and second-number can be anything

NPException18:01:53

if an argument is not a list, it's a number. If it's a number we don't need to do anything with it, so we can just return it.

roelof18:01:30

or we must do something like this :

(defn infix2 [[first-number operator second-number & r]]
  (if (empty? r)
    (list operator
          (if (list? first-number)
            (infix2 first-number)
            first-number)
          (if (list? second-number)
            (infix2 second-number)
            second-number
            ))
    (if (< (get priorities operator) (get priorities (first r)))
      (list operator first-number (infix2 (conj r second-number)))
      (infix2 (conj r (list operator first-number second-number))))))

NPException18:01:15

exactly :thumbsup:

roelof18:01:47

so this is right

roelof18:01:51

(* 3 (+ 2 (/ (- 5 3) 2)))

roelof18:01:30

lesson learned from today. Make problems even smalller then I do now

NPException18:01:40

That's always the hardest part in my opinion. Breaking down the problem into the smallest pieces that can be individually solved.

roelof18:01:07

I still have to learn that on my "old" age

NPException18:01:32

How old are you if I may ask?

roelof18:01:47

53 and on the 21 I will be 54

NPException18:01:48

A rare occasion where I don't feel old with my 34 then. 😄

roelof18:01:50

I think I deserve a break and maybe tomorrow or later the chapter about writing macros

roelof18:01:34

I hope this month I will finish the brave book and hopefully not feeling like a super beginner

roelof18:01:57

and in the far future learn web development with clojure if I then still like it

roelof18:01:19

again many thanks for the patience with a super beginner like me

NPException18:01:14

Feel free to contact me directly anytime if you have any questions or need help again.

NPException18:01:30

Also huge respect for your patience with that stuff. I think I took multiple breaks during those sections in the book.

roelof18:01:40

o, this is I think the 5th or 6th time I try

roelof18:01:09

and maybe I quit at chapter about functional programming

roelof18:01:45

and I were several times on a point I would quit but because of persons like you I see and learn things

roelof18:01:16

brave book is I think not the best learning book but it one of the best free ones

NPException18:01:58

It's the only beginner clojure book I have read, so I can't really tell how good it is compared to others. But it is the one that ultimately got me to work with Clojure fulltime, so it can't be too bad 😄

NPException18:01:16

There is currently a beginner meetup going on where participants read through the brave book, and then talk about it in occasional meetings to compare their exercise solutions and what they learned. Would this be something you'd be interested in?

roelof18:01:42

if I can fit into my schedule

roelof18:01:05

here is a lock-down so I have to play teacher for my daugther

NPException18:01:40

same here, though I only have my cats to feed in between their sleep schedule

roelof18:01:45

for me clojure is hobby to train my brain

roelof18:01:05

no idea if there are clojure jobs in the Netherlands

roelof18:01:33

my special need daugther is more important then a well payed job

NPException18:01:39

So you can probably just ask @asamonek here or on Twitter if you can join. Next meeting would be on 20.01. at 17:00 GMT+1. Topic for that meeting will be Chapter 3 of the book, so you are already ahead of the pack. 🙂

NPException18:01:14

> my special need daugther is more important then a well payed job Very true. Fortunately 2020 made it clear to pretty much every company that software developers can work from home. I worked from home with Clojure for a British company for the past 2 years.

roelof18:01:15

I have done that

roelof18:01:47

we see what the future wil bring

roelof19:01:20

my wife works now from March 2020 at home and she is not happy with it

roelof19:01:57

She misses her collegues (i think I wrote it wrong, so I hope you understand

NPException19:01:39

yeah understandable. Working from home is definitely less social than in office.

roelof19:01:11

are you doing web or other things were you use clojure

NPException19:01:43

backend for a website. Frontend was regular HTML+JS, but I didn't have to work on that.

NPException19:01:14

so everything between incoming requests and the database.

NPException19:01:31

and some smaller services around it, like for sending emails and notifications

roelof19:01:20

oke, when Im that far I like to write back-end for a gallery where the data is coming from the rijksmuseum api and a second project is a sort of crm for a volunteer organisation

roelof19:01:54

to keep track of payments, who has a subcription and if the subscriptions are payed or not

roelof19:01:02

but that will be later in the year

roelof19:01:39

first getting better in clojure and then look what I can use to make the two ideas work

roelof19:01:48

and I wil see if I also can make some challenges

NPException19:01:01

> I like to write back-end for a gallery where the data is coming from the rijksmuseum api and a second project is a sort of crm for a volunteer organisation sounds like great projects! I'd love to see them in action some day 🙂

roelof19:01:00

looked at the challenges of the writing macros and I hope I can solve them. right now I doubt it

roelof19:01:13

but it is almost time to lseep

NPException19:01:44

for me too. I'll be around in slack tomorrow again. see you 👋

roelof20:01:20

what do you then use for back-end writimng duct, pedestral or something else ?

NPException20:01:49

we use a whole bunch of individual Clojure and Java libraries, not a prepackaged framework. I don't remember many of the libraries though, I don't have access to the code to check atm. The ones I remember are • compojure • ring and various middleware • component • jsonista • clojure.java.jdbc • clj-time

roelof21:01:44

oke, some I know , I seen more cheshire instead of jsonista

roelof21:01:57

Im sure I need one of the two for the gallery project

roelof12:01:16

now the most difficult ones

(defn defattrs [& functions]
  '(do .....))

(def c-int (comp :intelligence :attributes))
(def c-str (comp :strength :attributes))
(def c-dex (comp :dexterity :attributes))

(defattrs c-int :intelligence
  c-str :strength
  c-dex :dexterity)

NPException12:01:16

I'm occupied with work atm, I'll probably be available in ~2 hours

roelof12:01:50

Not a problem

roelof12:01:03

im just thinking how to proceed further

roelof12:01:31

I never expect a quick answer. I expect a answer somewhere, sometime

Chase14:01:38

A test in this exercism problem wants this: (is (thrown? IllegalArgumentException (nth-prime/nth-prime 0))) and so far my code has this: (if (< n 1) (throw (IllegalArgumentException.)) which seems to do what I want but the test results tell me: Exception in thread main, syntax error caused by ... java.lang.IllegalArgumentException. tests failed

Chase15:01:00

hmm, but my else branch of the if is what solves the actual problem. I tried using a :pre condition but that didn't pass the test either.

Chase15:01:02

huh, now that I've actually instituted the else branch (I was just returning n while seeing if my exception logic worked) all tests pass. Sorry for wasting your time @jr0cket

Christian20:01:47

I have to supply a lot of functions that all do the same thing and was wondering how to make one function instead of a lot. Here is an example:

(defn count-a [s] (my-counter "a" s))
(defn count-b [s] (my-counter "b" s))
(defn count-c [s] (my-counter "c" s))
....
Is it possible to replace this somehow? Like having a function that can generate function names and if a user would call count-ß it would be replied with the correct function?

NPException20:01:14

Why not call (my-counter "XYZ" s) directly?

3
Christian20:01:35

Because the tests want the functions to be there.

Christian20:01:51

I think this might be my solution: https://stackoverflow.com/a/7854594/4919081 but I don't understand it

NPException20:01:49

So you would like to be able to do something like this?

(defcount "a")
;; now a function with the name count-a exists

Alex Miller (Clojure team)20:01:47

(defmacro defcount [x]
  `(defn ~(symbol (str "count-" x)) [s#] (my-counter ~x s#)))

(pprint (macroexpand-1 '(defcount "a")))

(clojure.core/defn
 count-a
 [s__155__auto__]
 (user/my-counter "a" s__155__auto__))

3
👀 3
Alex Miller (Clojure team)20:01:49

of course, if you're going to write a macro to make one function, you might want it to make many too

Christian20:01:19

Right, thats why the solution from the link with the doseq looks interesting

Alex Miller (Clojure team)20:01:33

yeah, it's just wrapping a doseq around the body basically

Christian20:01:03

So, when something is accessing my name-space, every function inside will be called. So when the function is making functions, these will be available? what happens if I leave something that prints? will it be printed everytime someone uses my namespace?

andy.fingerhut20:01:56

All top level forms in a namespace are evaluated when you require or use a namespace. If some of those cause printing, then that will happen

andy.fingerhut20:01:50

Print statements inside of defn forms are not evaluated until the function is called, but print at top level, or in do doseq etc will all be evaluated at require time

andy.fingerhut20:01:34

If a top level form in a namespace executed a loop, and each iteration of that loop causes something to be defn’d, then that will happen at the time the namespace is required

🙌 3
3
yiorgos21:01:10

I am currently learning about Components and while googling I came across this example app https://github.com/seancorfield/usermanager-example/ In the WebServer component they associate a promise in the map here https://github.com/seancorfield/usermanager-example/blob/develop/src/usermanager/main.clj#L165 What is the motivation of doing that?

dpsutton21:01:24

when running from main that will block waiting for the promise to be delivered, which only happens when the component shutsdown. so in practice, this will just never be fulfilled and the webserver runs forever.

seancorfield21:01:15

But it also allows you to shutdown the server via code if you need to.

yiorgos21:01:56

I am not sure I understand. I thought in -main they start the server but the comment says the opposite

seancorfield21:01:42

The component is started, which starts the web server, and then the promise is pulled out of that component and waited on.

👍 3
seancorfield21:01:38

In normal operation, it'll just wait forever. But you could deliver the promise via a REPL to shut it down.

seancorfield21:01:50

Or you could just start/stop the component yourself in the REPL.

dpsutton21:01:54

i don't see how you could shut it down in code though. you'd need access to the component that started to get access to that promise?

dpsutton21:01:08

(when invoked from -main and a repl is used i mean)

seancorfield21:01:43

When we started out, we used this pattern, along with code that allowed a specific URL to be hit with certain params to deliver the promise (and shut the process down).

yiorgos21:01:44

> The component is started, which starts the web server, and then the promise is pulled out of that component and waited on. I think that makes sense now. Thanks!

dpsutton21:01:58

ah, not this code but a similar pattern

dpsutton21:01:16

i was scouring it wondering what i was missing 🙂

seancorfield21:01:31

More recently, we tend to record the started component into a top-level Var so it can be manipulated via a remote REPL more easily.

seancorfield21:01:10

I've been meaning to clean up how the usermanager example works to better match what we do at work.

seancorfield21:01:48

It seems like having conditional logic to either start Jetty or http-kit is confusing for folks -- but it was done to show how easy it is to switch web servers.

yiorgos21:01:41

Is Component the most popular library for that kind of pattern? I see there are Integrant, Mount, Clip that pop up when googling

seancorfield22:01:41

I think Component is the most popular, yes. And certainly the simplest.

👍 3
seancorfield22:01:48

Integrant has, I think, seven lifecycle hooks (compared to Component's two). Mount relies on global data (which just completely discounts it as a choice for me). I haven't looked at Clip.

yiorgos22:01:20

Thank you very much!

seancorfield22:01:48

Now that I think about it, the promise was added to make it easier to switch between Jetty and http-kit. Jetty by default blocks the main thread when you start it and you have to say :join? false to have it be non-blocking; http-kit is non-blocking by default. That's what you want for REPL usage. But for -main usage, you want some sort of blocking behavior -- otherwise you start the server and then immediately fall off the bottom of -main and the server shuts down. Adding the promise means that -main can wait on it, regardless of the web server in use. Shutting down the system doesn't matter much in -main since the process is most likely going to stay running until it is externally killed. But in the REPL you're going to start the component (and the web server in a non-blocking way) and then later shut the component down when you're done (and so the promise doesn't really matter). I'll clean up the docs around that when I simplify the example.