Fork me on GitHub
#beginners
<
2020-02-02
>
jesse.claven00:02:57

Hey! I’m going through http://pedestal.io/guides/your-first-api and I’m at the user=> (require 'main) part but I’m receiving an error of:

Syntax error (FileNotFoundException) compiling at (main.clj:1:1).
Could not locate io/pedastal/http__init.class, io/pedastal/http.clj or io/pedastal/http.cljc on classpath.
I’ve triple-checked and I have my deps.edn and src/main.clj correct. I’ve also just gone through https://tomekw.com/clojure-deps-edn-a-basic-guide/ without any problems, leading me to think that my environment is alright

ghadi00:02:27

check your spelling on that namespace @jesse.claven

ghadi00:02:38

ped`e`stal

ghadi01:02:31

(in the require declaration)

jesse.claven01:02:13

:man-facepalming::skin-tone-3:

jesse.claven01:02:37

I knew it would be something silly, haha. Thank you @ghadi. This is what I get for starting a tutorial at 1am on a Saturday

ghadi01:02:50

it happens :)

jesse.claven01:02:12

to the best of us, I’m sure 😉 haha

munichlinux03:02:25

Hi Clojurians, I come from javascript/python world. I am trying to understand how the recursion works in clojure. ((fn foo [x] (when (> x 0) (conj (foo (dec x)) x))) 5) here is how I would write in javascript: function anon(x) { if (x >0) { return [x].concat(anon(x - 1)); } return []; } In JavaScript, I do write the case for when x === 0, which is my terminating case. Why does clojure return ‘(5 4 3 2 1) and not ’(5 4 3 2 1 nil)?

nate_clojurians03:02:06

because (conj nil 1) returns (1)

nate_clojurians03:02:07

you might want to look at loop and recur

nate_clojurians04:02:46

recursion via calling the current function can be dangerous since clojure doesn't have tail call elimination, meaning you can make the stack level too deep and cause an exception, and loop/recur works around that

eagonmeng04:02:39

@munichlinux Also consider using the sequence abstractions/library, and try to move away from thinking in terms of loops

(reverse (range 1 6)) ;; sequence functions for working with/iterating over numbers
(take-while pos? (iterate dec 5)) ;; a minimal example of all the logic in your function

munichlinux05:02:03

@nate_clojurians Thanks, that makes sense. I was trying https://clojurecademy.com/, the example was part of that question.

munichlinux05:02:33

@eagonmeng

(take-while pos? (iterate dec 5)) 
that looks pretty good. Thanks for that.

hindol.adhya10:02:55

Be aware that for very hot loops, loop/recur can be significantly faster as it does not have the overhead of creating sequences. Normally won't matter though.

neo255111:02:55

Is it possible to decorate all functions in a namespace and redefining them in place? For debugging I would like to log/print the input/output of some function in a defined namespace in a running app. I thought alter-var-root might work but I am unsure.

jumar12:02:50

Cider can do this automatically and I think it just wraps a library.

neo255115:02:12

Thanks a lot!!

borkdude11:02:58

@software.dev0218 I now added a Windows build for jet: https://github.com/borkdude/jet/releases/tag/v0.0.11

borkdude12:02:10

It can now also be installed using scoop: https://github.com/borkdude/jet#windows

borkdude17:02:24

@software.dev0218 I now also added clojure.edn to the npm package of sci:

> evalString("(require '[clojure.edn :as edn]) (-> \"{:a 1}\" edn/read-string clj->js)")
{ a: 1 }

software.dev021821:02:48

Absolutely! 🙂

borkdude11:02:32

(so you now have three ways of converting EDN to JSON: jet, babashka via cli or sci as an npm lib)

pez11:02:43

TIL; There is something called http://exercism.io, and there is a Clojure track: https://exercism.io/my/tracks/clojure

hindol.adhya13:02:43

Yes, and I can't recommend it enough for beginners.

pez13:02:55

I got stuck on the 17-digit Armstrong numbers test.

pez16:02:26

Cool solution! I just got mentored to find the problem with my solution. Plus some other nice pointers. Such an awesome service. My solution: https://exercism.io/tracks/clojure/exercises/armstrong-numbers/solutions/585ac5a4d0594cd7a2dd36679f8c4494

hindol.adhya19:02:48

If I may, Character/digit is a better way of converting char to digit, which I also did not do.

pez19:02:55

You may! Thanks!

georghagen14:02:10

Hello! I am trying to traverse a vector with map, and convert any string found to a key: This is the function I am trying to use with map:

(defn cs2k
  [v]
  (if (= v str)
    (keyword v)
    v))
This is my vector I am trying it on: [“string” 3 5]

alpox14:02:11

@georghagen I believe you were then looking for (string? v) instead of (= v str)

zdot10114:02:53

yea, (= v str) is asking if v is itself the function str , rather than asking if v is a string

georghagen14:02:29

Thank you guys! I am still a bit syntax-confused 😃 Guess I should do more koans

andy.fingerhut19:02:01

No problem asking in the #beginners channel about such things, and not trying to discourage you from practice, but str in Clojure is a function you can call, usually to create a string that represents the arguments you pass to it. The expression (= v str) determines "Are the values of v and str equal to each other?", i.e. "Is v equal to the function that is the value of str?"

andy.fingerhut19:02:11

There are a lot of functions in Clojure, and it isn't always clear which one to use when you are new to it. The Clojure cheatsheet might be helpful for you, because it at least tries to divide up the list of Clojure's built-in functions and macros into logically related groups: http://jafingerhut.github.io

georghagen19:02:59

Thank you for a good explanation! It’s only encouraging to get comments like that

peb.brzezinski19:02:15

Hey! I’m super new to clojure, and am working through I like it a lot so far, but I’ve a bit stuck and am not sure how to proceed. There’s an exercise that asks me to create a function mapset that takes a function and vector as params and does the same thing that map does but returns a set instead. This is what I tried

(defn mapset
                     [fn v]
                     (loop [remaining v
                            result-set (hash-set)]
                       (if (empty? remaining)
                         result-set
                         (let [[head & tail] remaining]
                           (recur remaining
                                  (into result-set
                                        (set [fn head])))))))
and I feel I’m “almost” there but it doesn’t work. Any help appreciated!

zdot10119:02:43

If I'm reading this right, the first error I see is recurring on remaining each time, instead of tail, since the latter would be the 'rest' of the vector you have yet to have worked on (and remaining refers to your beginning state with the full vector, so if you keep recurring on it, you never are moving forward). The second is [fn head] instead of [(fn head)]

zdot10119:02:58

where the latter will call the function on head, and the former will be adding fn itself into the set

zdot10119:02:27

so the fix would be

(defn mapset 
                      [fn v] 
                      (loop [remaining v 
                             result-set (hash-set)] 
                        (if (empty? remaining) 
                          result-set 
                          (let [[head & tail] remaining] 
                            (recur tail 
                                   (into result-set 
                                         (set [(fn head)])))))))
I believe

zdot10119:02:34

I should check that though to be sure ahaha

zdot10119:02:58

yea so far that works on my side

peb.brzezinski19:02:19

So I was almost there lol

peb.brzezinski19:02:30

Stupid mistake, thanks @zdot101!

peb.brzezinski19:02:44

Just to confirm that I understand it right. The recur tail only runs within the let [[head & tail]… block? Or does it re-run whole mapset?

ghadi19:02:03

neither, recur goes to the nearest loop header

ghadi19:02:39

an fns are implicit loop headers

peb.brzezinski19:02:43

That makes sense. Thank you.

zdot10119:02:57

other small things: I may be missing something, but I don't think you need to call (hash-set) , and can instead use the first class syntax for sets (ie, writing #{} in its place). Also, instead of (into result-set (set [(fn head)])), you should be able to just call (conj result-set (fn head)) , where the latter is flat out just saying "add (fn head) to set" and the former is saying something like "create a vector containing just (fn head) , then immediately turn it back into a set, and conjoin these two sets"

peb.brzezinski19:02:46

Awesome, good feedback, thank you very much.

peb.brzezinski19:02:02

I still find lisp’s syntax a bit confusing 😛