Discipline, good design, good test coverage, good variable names, documentation on functions and vars, always be using the REPL, that's mostly how
There's some refactoring support in editors, but I consider those "easy" refactors, harder ones where you change things in backward incompatible ways the editor won't do those for you π
(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?
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
.
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.
So this
(map f [1 3] [2 4])
is roughly equivalent to
[(f 1 2)
(f 3 4)]
Does this help you?
i will try on my code and let you know π
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')
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)
I'm occupied with work atm, I'll probably be available in ~2 hours
Not a problem
im just thinking how to proceed further
I never expect a quick answer. I expect a answer somewhere, sometime
'(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
.
oke, but this was also not right I think : (list '(read-string "my-text"))
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.
You only need to quote read-string
.
So what it's asking for is this: (list 'read-string "my-text")
Getting used to quoting can take a while π
yep and figure out when something needs to be surrounded by parentheses also π
Am I right that only "Roelof" is printed here
(list 'read-string "Roelof Wobben, Star Wars")
(eval (list 'read-string "Roelof Wobben, Star Wars"))
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?
not that I know
but this is the page everything is explained : https://www.braveclojure.com/read-and-eval/
Ah, braveclojure! I learned the language from there about 3 years ago. π Maybe I have my exercise code still lying around somewhere
I use it now for some 2 weeks to learn clojure but for every challenge I needed some help. Very frustating
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)"))
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.
yep, that prints out a list with the two data
yep, I know
I did try to make it and got the wrong answer
I thought this was equal (1Β +Β 3Β *Β 4Β -Β 5)
and (-Β (*Β 4Β (+Β 1Β 3))Β 5)
but it is not
and this one is given me the right output : (-Β (+Β (*Β 4Β 3)Β 1)Β 5)
so with the knowlegde that I have I never can make a general solution
(-Β (*Β 4Β (+Β 1Β 3))Β 5)
does not equal (1 + 3 * 4 - 5)
, *
needs to take precedence over +
.
yep, as I said I noticed
I can give you a link to my solution for the second exercise, if you want something to compare against.
Thanks, But first I will try it on my own
I think I have to start over again
make things to complicated
(defn infix [expr]
(let [splitted (str/split (subs expr 1 (- (count expr) 1)) #" ")]
))
do you take the expression as a string?
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.
yep, that was my idea and then split it on the space and delete the parentheses
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 :
(\- (\+))
as expected. You are creating a list, consisting of the sixth element, and a nested list with the second element.
second element is +
, sixth is -
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 answerI only have to adapt it to the whole formula
are you still passing expr as a string?
yep (evalΒ (infixΒ "(1Β +Β 3Β *Β 4Β -Β 5)")Β )
do (evalΒ (infixΒ '(1Β +Β 3Β *Β 4Β -Β 5)))
instead, then you can omit your read-string
and str
calls
you need to adjust your nth
indices then, too.
yep, I see
I know get a out of bounds error
I assume your indices are off by 1 now.
nope,
Still a out of bounds error
can you paste your current code ?
(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))
off by 1. indices start at 0, so your second element will be at index 1 and so on.
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)) )
; Syntax error (IllegalArgumentException) compiling at (chapter7.clj:28:1).
; Can't call nil, form: (nil)
which line is line 28?
the eval
line
(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.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))
Thanks,
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)))
congrats!
Now next step would be to make it work for other formulas, like (3 * 2 - 1)
and others
I do not know if I can make that work
then you have to make something that looks for a order
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.
This was my priority map, just to give you an idea: (def priorities {'+ 1, '- 1, '* 2, '/ 2})
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.
I tried with map and that helped π sorru for late reply, wanted to complete the functionality
this is I think a nice lesson
may I choose what op1 and op2 are
and maybe use a regex to split it into pieces ?/
(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')
you are trying to use strings again
keep in mind that expr
is just a list of alternating values and operators.
so no. regex bad. (in this case at least π)
Also I'd like to point you at a section in a previous chapter: https://www.braveclojure.com/do-things/#Destructuring
you can destructure your expr
in the parameter list of the function for easy access to the elements of it.
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
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)
but what if I do (+ 1 2)
or (1+2+3+4+5+6)
then this destructering does not work
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
It does work, but we can get to it after we made your approach work. π
oke
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)]
and I know that 2 4 6 are the operators
the rest I do not see
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.
oke, im curious which way this is going to
So how can you remove the first 3 elements from expr
to get a (potentially empty) list of all remaining elements?
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.
(drop 3 expr)
π
oke
we have then this :
(defn infix2 [expr]
(let [first (first expr)
second (nth expr 1)
thirth (nth expr 2)
r (drop 3 expr)]
))
so then a check if r is empty ?
yeah
oke we know then that second is the parameter and one and three the numbers
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.
so we can do (list second first thirth)
yes
oke , any recoomendations then for a better name ?
@chase-lambert try or
instead of if
maybe a op1 b
?
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.
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.
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)
))
for the second case we need the priorites
variable
I think
correct
there I have to think well
Right now we do not know the second operator
so we cannot compare anything
if r
is not empty, where will the second operator be?
in r
more precisely it will be the first element of r.
yep, you are right
Also I just noticed your if
does not surround the (list ..
below it
oke, then now I have to figure out how I can find the priorities
changed
BRB
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.
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 π
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
I will say i to you iof you help me too much
oke
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"
))))
exactly
now I think I need to work on paper what schould happen now
so I need some moments I think
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) `
so it does not matter
hmm, im still thinkimg I need to join the second-number back to r when r is not empty
partially correct. only if the second operator has a higher priority
hmm, Im stuck
in the first case I would do something like (list operator(list (infix2 r second) first-number)
but that would not work because then the first-number will be the operator and that is not good
let's first deal with the (in my opinion) easier case, which is the second case.
oke
How would you do that?
(infix2 r (operator first-number second-number) `
but that cannot be good because infix2 wants only 1 argument and now there are 2
or I can do (infix2 (list r (operator first-number second-number)
not quite. You need to prepend (operator first-number second-number)
to r
, and pass that into infix2
sorry I mean (list operator first-number second-number)
oke , so (infix2 (conj r (list operator first-number second-number))
?
yeah, that should do it
now the second one
we need something like (list operator(list (infix2 r) second-number) first-number)` ?
because we do not have the operator and the other number
let's break it up. What would the nested call to infix2 look like?
im still thinking (infix r second-number)
bcause r has the operator and the number we are missing
yes, but infix2 only takes one argument, so you need to prepend second-number
to r
oke so (index (conj r second-number))
infix2 instead of index, but yeah π
sorry
I want to type faster then i can
brb
so the call will be (list operatotor (list (infix2 (conj r second-number))) first-number)
I hope I did not miss any parentheses
something not right with parentheses here :
(infix2 '(10 + 2 * 3))
(+ ((* 2 3)) 10)
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)))))))
there are 2 issues here
(list operator (list (infix2 (conj r second-number))) first-number)
1. you don't need to put the nested infix2 in another list
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)))))))
(infix2 '(10 + 2 * 3)) gives (+ (* 2 3) 10)
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))
)
(infix2Β '(2Β *Β 3Β +Β 10))
gives also (+Β (*Β 2Β 3)Β 10)
well done!
pff, still have the feeling that I have to learn a lot how to approach this sort of problems
and thanks for the patience with me for the whole day
That comes with time and practice
ah, no worries, I was only playing games on my main monitor most of the time π
I would like to quickly go back to the topic of destructuring if you have a few more minutes
hmm, one thing im still not happy
sure, what's it?
(infix2Β '(10Β +Β 2Β *Β 3))
gives (+Β 10Β (*Β 2Β 3))
which is correct
where
(infix2Β '(2Β *Β 3Β +Β 10))
gives (+Β (*Β 2Β 3)Β 10)
which is also correct
why on the second one is the 10 in the last position
can we not look both the same
or am I overthinking ?
if you imagine replacing 2 * 3
with 6 ->
(10 + 6) -> (+ 10 6)
(6 + 10) -> (+ 6 10)
it's just keeping the order of arguments like they were in the original expression. Which is expected in my opinion.
You don't want it to accidentally re-order the arguments to a division or subtraction.
Now that I think about it, that is the actual important reason for the 2) issue I mentioned earlier. :thinking_face:
oke
and never knew that recursion could solve so many problems
yeah, I never used it much when I was working with Java, but now I use it quite regularly
oke, I know ik from haskelll where it is also used very often
java I do not have learned
pnl;y some haskell., some c# and some ruby
and for practice I do now the brave book and exercism
later on maybe 4 clojure and maybemuch later Advent of Code
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))))))
oke and it still then works ?
I thougth I need a let to deconstruct
I thought that as well at first, but destructuring works in quite a few places
yep, it does
learned another "trick"
want a small extra challenge? π
always. as lomg as I can do it with the knowlegde I get from the book
I only do not know if I got it working today
almost dinner/supper here
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)))
there is only one spot that needs to be changed
In case the book did not mention it yet: To check if something is a list, you call (list? the-thing)
oke, from the c# time I learned on OOP its not good to ask a object what it is
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.
i know
just thinking how to to solve this
I see what needs to be changed
; (* 3 (+ 2 (/ (- 5 3) 2))) => current outcome
; (* 3 (2 + (5 - 3) / 2)) => preffered outcome
thinkingg I might need another if then to solve this
technically correct, but maybe not in the way you think right now. Where would you put that if and what would it check for?
I was thinking just before the if then we have now and it would do a check if first number is a list
why do you want to check it there?
just a feeling what is the right place
now what would you do if the first argument is a list and not a number?
because It think both cases which we have now could hit this problem
then we have a parse that again somehow
What we are making is a parser as far as I see it
not really
am I on the right track or not ?
if an argument is a list, (so a nested expression) we want to turn it into its infix representation.
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.
I think you mean like here : (listΒ operatorΒ first-numberΒ second-number)
be back after supper/dinner
I still miss something I think
you want a if then into that part ?
yep exactly. one for each first-number
and second-number
oke
so like this :
(list operator (if (list? first-number) ....) (if (list? second-number) ....)
??
yup
oke, then I have to think how to proceed then
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))))))
and this is not going to solve it
(ns chapter7
(:require [clojure.core.match :refer [match]]))
you are thinking to complicated π
π’
match is a cool thing, but definitely not needed here
let's rename first-number
to a
and second-number
to b
for now, makes it easier to write about π
hmm
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)))))))
but then I need on both cases a else branch
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)))))))
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.
keep in mind that everything is an expression. Those nested ifs do not directly return from your infix2 function.
oke
(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))))))
; 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')
you also shouldn't nest the (if (list? second-number)
in the check for the first one
instead:
(list operator
(if (list? first-number)
(infix2 first-number)
)
(if (list? second-number)
(infix2 second-number)
))
so no else on the first if then
both ifs are independent of each other.
I thought that was needed
There is an else needed for both of them
I just don't want to give it to you straight away π
and im nowvery confused
if first-number is not a list then we cannot know if second-number is a list of not
so what schould then be in the else of that one ?
first-number and second-number can be lists or numbers completely independent of each other
(1 + 2) ((1 * 3) + 2) (1 + (5 *2))
in all those cases operator
is the +
, and first-number and second-number can be anything
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.
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))))))
exactly :thumbsup:
so this is right
(* 3 (+ 2 (/ (- 5 3) 2)))
yes π
π
lesson learned from today. Make problems even smalller then I do now
That's always the hardest part in my opinion. Breaking down the problem into the smallest pieces that can be individually solved.
yep
I still have to learn that on my "old" age
How old are you if I may ask?
53 and on the 21 I will be 54
A rare occasion where I don't feel old with my 34 then. π
I think I deserve a break and maybe tomorrow or later the chapter about writing macros
I hope this month I will finish the brave book and hopefully not feeling like a super beginner
and in the far future learn web development with clojure if I then still like it
again many thanks for the patience with a super beginner like me
Feel free to contact me directly anytime if you have any questions or need help again.
Also huge respect for your patience with that stuff. I think I took multiple breaks during those sections in the book.
o, this is I think the 5th or 6th time I try
and maybe I quit at chapter about functional programming
and I were several times on a point I would quit but because of persons like you I see and learn things
brave book is I think not the best learning book but it one of the best free ones
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 π
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?
could be
if I can fit into my schedule
if you are on Twitter: https://twitter.com/asamonek/status/1344913238933315585
here is a lock-down so I have to play teacher for my daugther
same here, though I only have my cats to feed in between their sleep schedule
lucky you
for me clojure is hobby to train my brain
no idea if there are clojure jobs in the Netherlands
my special need daugther is more important then a well payed job
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. π
> 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.
I have done that
oke
we see what the future wil bring
my wife works now from March 2020 at home and she is not happy with it
She misses her collegues (i think I wrote it wrong, so I hope you understand
yeah understandable. Working from home is definitely less social than in office.
are you doing web or other things were you use clojure
backend for a website. Frontend was regular HTML+JS, but I didn't have to work on that.
so everything between incoming requests and the database.
and some smaller services around it, like for sending emails and notifications
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
to keep track of payments, who has a subcription and if the subscriptions are payed or not
but that will be later in the year
first getting better in clojure and then look what I can use to make the two ideas work
tomorrow study this page : https://www.braveclojure.com/writing-macros/#Exercises
and I wil see if I also can make some challenges
no hurry
> 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 π
who knows
looked at the challenges of the writing macros and I hope I can solve them. right now I doubt it
but it is almost time to lseep
for me too. I'll be around in slack tomorrow again. see you π
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?Why not call (my-counter "XYZ" s)
directly?
see you
Because the tests want the functions to be there.
I think this might be my solution: https://stackoverflow.com/a/7854594/4919081 but I don't understand it
what do you then use for back-end writimng duct, pedestral or something else ?
So you would like to be able to do something like this?
(defcount "a")
;; now a function with the name count-a exists
yes!
(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__))
of course, if you're going to write a macro to make one function, you might want it to make many too
Right, thats why the solution from the link with the doseq looks interesting
yeah, it's just wrapping a doseq around the body basically
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
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?
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
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
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
oke, some I know , I seen more cheshire instead of jsonista
Im sure I need one of the two for the gallery project
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?
https://github.com/seancorfield/usermanager-example/blob/develop/src/usermanager/main.clj#L232
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.
But it also allows you to shutdown the server via code if you need to.
I am not sure I understand. I thought in -main they start the server but the comment says the opposite
The component is started, which starts the web server, and then the promise is pulled out of that component and waited on.
In normal operation, it'll just wait forever. But you could deliver the promise via a REPL to shut it down.
Or you could just start/stop the component yourself in the REPL.
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?
(when invoked from -main and a repl is used i mean)
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).
> 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!
ah, not this code but a similar pattern
i was scouring it wondering what i was missing π
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.
I've been meaning to clean up how the usermanager example works to better match what we do at work.
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.
Is Component the most popular library for that kind of pattern? I see there are Integrant, Mount, Clip that pop up when googling
I think Component is the most popular, yes. And certainly the simplest.
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.
Thank you very much!
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.