Fork me on GitHub
#beginners
<
2016-09-16
>
eslachance04:09:06

Hmm. Before I go too far into this very long process of defining this huge hash-map I must ask. I need to store what amounts to a "tree" of API endpoints, where some parts of the URI are variable. I think hash-map is what I need but I'm not sure. In Javascript this is a simple object:

const API = ``

const Endpoints = {
  login: `${API}/auth/login`,
  guilds: `${API}/guilds`,
  guild: (guildID) => `${Endpoint.guilds}/${guildID}`,
  guildIcon: (guildID, hash) => `${Endpoints.guild(guildID)}/icons/${hash}.jpg`,
}

eslachance04:09:33

As you can see... each part is a build on the previous one and includes variables. I'm not 100% sure if what I'm doing is right.

(def API "")
(def endpoints
  {:login (str API "/auth/login")
   :guilds (str API "/guilds")
   :guild (str :guilds "/" :guild-id)})

eslachance04:09:55

In fact I'm pretty sure it's wrong. Can anyone just give me a single example (like the guild using an ID) and how to call it?

eslachance04:09:15

(and also tell me if hash-map is the right data structure or if not, what I should be using)

kauko05:09:31

So where it says :guild (str :guilds "/" :guild-id), you'd like :guilds to have the value (str API "/guilds")?

plexus07:09:36

@eslachance in the JS version it's using anonymous functions for guild and guildIcon. That's necessary in order for Endpoints to be able to reference itself. You can do the same in Clojure

plexus07:09:12

(def API "")

(def endpoints
 {:login (str API "/auth/login")
  :guilds (str API "/guilds")
  :guild #(str (:guilds endpoints) "/" %)
  :guildIcon #(str ((:guild endpoints) %1) "/icons/" %2 ".jpg") })

filipecabaco08:09:29

hey guys, trying to improve my clojure by doing simple stuff and while implementing sieve prime calculation I’m getting an error that I wouldn’t expect from tail optimized calls:

(defn rem? [x y] (and (not= x y) (= 0 (rem x y))))
(defn sieve
    [limit]
    (loop [step 2
          acc (take limit (iterate inc 2))]
      (if (>= step limit)
        acc
        (recur (inc step) (remove #(rem? % step) acc)))))

(sieve 10000)
This returns StackOverflowError clojure.core/seq--4357 (core.clj:137) and I’m really not sure why… could you guys help me out understand what’s wrong in my code?

sveri08:09:01

@filipecabaco Hm, just a quick shot after a first look, maybe remove is lazy and keeps a reference to the list?

plexus08:09:37

yup that seems to be it, wrap the remove in doall and it works

filipecabaco08:09:31

Ok will try! Thanks guys!

filipecabaco08:09:17

Completely forgot about laziness of remove... 😕

sveri08:09:28

yea, its easy to do so

sveri08:09:10

@filipecabaco There was an interesting discussion about lazyness versus datastructures on the ML lately: https://groups.google.com/forum/#!topic/clojure/znPyDzGkBgA

sveri08:09:27

Especially @alexmiller posts were very interesting

val_waeselynck08:09:02

@filipecabaco some feedback and tips:

val_waeselynck08:09:24

instead of (take limit (iterate inc 2)), you'll probably want to use the range function

filipecabaco08:09:20

Range gives me a 0 and I has a mod that would return division by zero

filipecabaco08:09:35

Not sure how rem will handle it but can also try

val_waeselynck08:09:40

not if you use (range 2 limit)

val_waeselynck08:09:29

(well to be completely isofunctional (range 2 (+ limit 2))

filipecabaco08:09:48

@sveri will take a look

val_waeselynck08:09:46

also, interestingly, for this algorithm, step doesn't need to iterate over all the integers (e.g step = 4 adds nothing to the work done by step = 2); it would be interesting to find a way use your partially-computed sieve to pick the next step at each iteration 🙂

filipecabaco08:09:18

True... That's wasted computation...

sveri08:09:53

No problem, just throw more cores at it :D:D

plexus08:09:47

@val_waeselynck is right, this version is about 7 times faster for me

plexus08:09:55

(defn sieve
   [limit]
   (loop [step 2
          acc (take limit (iterate inc 2))]
     (let [step (first (drop-while #(< % step) acc))]
       (if (nil? step)
         acc
         (recur (inc step) (doall (remove #(rem? % step) acc)))))))

filipecabaco08:09:45

A small change that makes a giant difference... Awesome stuff! Really appreciate it guys 👍

willyfrog11:09:09

if I need to run a cron job, could cljs be used for that? or should I better try lein-exec?

plexus11:09:50

@willyfrog you could use CLJS or lein-exec, but that's kind of a false equivalency

plexus11:09:28

CLJS is just a compiler, the question is how you will run that cljs/js. you can run a cljs script directly with Planck, or compile to JS and run it e.g. with node

willyfrog11:09:57

I was thinking to compile it to js and run it from there, but I’m just guessing

plexus12:09:47

yeah you can do, what will you use to run it?

willyfrog12:09:14

I haven’t checked cljs, but I thought it could be run using node

willyfrog12:09:00

I started the project with lein-exec, but seems a bit slow having to spin the jvm, so I thought that might be a good alternative

willyfrog12:09:24

But I’m a bit new on many aspects, starting clojure and I haven’t done anything in cljs, so I prefer to ask before wasting too much time in something I’m not sure if it’s doable or if it even would save me any troubles

plexus12:09:25

Doable, definitely. And once it's compiled it will start up much faster than JVM+Clojure (most of the startup time is not really the JVM booting, it's Clojure that's loading)

plexus12:09:13

but... (sorry, there's a but), it does add extra complexity. You'll have to get somewhat familiar with the CLJS tooling, figure out how to do things on a JS based platform. Here it really depends on what your cron jobs tries to do.

plexus12:09:37

you might face some early frustration as you figure this out is all I'm saying

willyfrog12:09:03

get some data from an api, do a couple of queries on a database and show some results

plexus12:09:58

right, both of those things will have to be done in a different way than on Clojure, you can't just take your existing code from one to the other

sveri12:09:19

@willyfrog does startup time matter? I mean, does it make a difference if that cron job takes a few seconds to start or not?

plexus12:09:43

yeah was gonna say that as well 🙂

sveri12:09:56

A cron job runs every x seconds, which is exactly what it will do, just with a given startup time which is the same

dominicm12:09:37

Haven't tested this, but Clojure can run a good amount faster if you AOT the jar first too, which might reduce the startup time consideration

sveri12:09:51

TBH, I never understood all the complaining about startup time, in almost 3 years this has not been a problem for me. That said, it could be one if I wanted to make cmd line tools with clojure. Or, if I wanted to create android apps, which I both dont do.

dominicm12:09:03

I've seen applications (such as https://github.com/snoe/clj-refactor.nvim) which uses the node/npm for dependencies and runs cljs within node.

dominicm12:09:41

@sveri One time I wanted to build a command line tool, that's where it bites I think

dominicm12:09:07

I ended up dealing with python, I look forward to trying Planck some day though

sveri12:09:40

yay, python is it, or any of the thousand bash tools

willyfrog12:09:57

yeah, I might be being a bit too picky, but was wondering the options available and if it makes any sense what i was thinking

willyfrog12:09:17

I might keep going with lein-exec 🙂

sveri12:09:49

I myself would try to avoid everything that has to do with javascript interop, but again, thats just my opinion which in that case, is not based on facts

dominicm12:09:11

@willyfrog lein-exec/boot are good options for running scripts in that way.

plexus12:09:31

it allows you to have a single JVM running, and each cron job just connects to it

willyfrog12:09:05

I’ll try and check both 🙂

dominicm12:09:07

@plexus Would a scheduled operation inside Clojure make more sense in that case? If the JVM is up either way.

plexus12:09:47

you mean scheduling it inside the JVM? you can do that, I don't have a strong opinion on that one 🙂

sveri12:09:33

@dominicm you will have to consider what happens when the jvm crashes, you will need some kind of watching service that restarts it then

dominicm12:09:14

@sveri Same with Grenchman. Systemd does make restarting easier now.

sveri12:09:27

yea, a cronjob would restart just everytime

willyfrog12:09:30

thanks for your answers, I’ll try to check every option 🙂 instead of cljs.

eslachance13:09:20

Thank you @plexus , I appreciate the help! (from 7 hours ago!)

plexus14:09:59

You're most welcome ^^

eslachance15:09:49

@plexus Hmm just one question though if you don't mind. How do I "call" it? say I have a guild ID and icon hash (the last line for guildIcon) how would I build it somewhere else in the code? (I know I know, still a noob question)

plexus15:09:40

((:guildIcon endpoints) "the-guild-id" "the-icon-hash")

eslachance15:09:44

Awesome. Thank you very much!