Fork me on GitHub
#beginners
<
2018-09-13
>
dangercoder05:09:52

Does Sente (https://github.com/ptaoussanis/sente/) require you to have UI/SERVER in the same leiningen project? Only saw that composition in example projects. Is it possible to route it to my own specified port, host? aka not the same port as the ui

4
dangercoder05:09:50

It's currently trying to go to:


dangercoder05:09:36

Think I solved it by myself. Will probably make a PR to Sente/Examples showing how to set it up with a seperate UI and API project. from the docs for

make-channel-socket-client!
`
Common options:
       :type           ; e/o #{:auto :ws :ajax}. You'll usually want the default (:auto).
       :protocol       ; Server protocol, e/o #{:http :https}.
       :host           ; Server host (defaults to current page's host).
       :params         ; Map of any params to incl. in chsk Ring requests (handy
                       ; for application-level auth, etc.).
       :packer         ; :edn (default), or an IPacker implementation.
       :ajax-opts      ; Base opts map provided to `taoensso.encore/ajax-lite`.
       :wrap-recv-evs? ; Should events from server be wrapped in [:chsk/recv _]?
       :ws-kalive-ms   ; Ping to keep a WebSocket conn alive if no activity
                       ; w/in given msecs. Should be different to server's :ws-kalive-ms."

Yehonathan Sharvit08:09:05

A question related to def. Could you explain in simple words why calling defining twice the same variable is not prevented by Clojure?

borkdude09:09:14

@viebel isn’t that the idea behind reloadable code?

Yehonathan Sharvit09:09:37

@borkdude Yes. But it confuses beginners when we say that Clojure on one hand encourages immutability and on the other hand allows you to redefine what is already defined

borkdude09:09:32

it has to do with the REPL workflow. this is the first thing a beginner should learn.

borkdude09:09:50

if you don’t want reloading of defs, you should use defonce

Yehonathan Sharvit09:09:43

Do you have good material about: 1. the importance of REPL workflow 2. The details of REPL workflow

lispyclouds09:09:53

@viebel using def isnt exactly an assignment like other languages. its like a binding that gives a name to a memory location.

(def value 5)
(def value (+ value 1))
this case doesnt really mutate value. a completely new memory location with the value of 6 is allocated and is now called value again. so yes clojure is still immutable even with multiple defs on the same name.

borkdude09:09:20

that’s also a way to look at it, but fundamentally vars are mutable, e.g. you can call alter-var-root on them

lispyclouds09:09:53

correct. but i guess that is not advisable?

borkdude09:09:35

depends 🙂

Yehonathan Sharvit10:09:14

@rahul080327 @borkdude What is the fundamental difference between def and alter-var-root beside the fact that the latter is atomic and apply to its current value?

borkdude10:09:51

@viebel I think as lispyclouds pointed out, when you re-def something with the same name, the old var isn’t re-used

Yehonathan Sharvit10:09:34

But what is the difference between not reusing the old var and creating a new var with the exact same name?

Yehonathan Sharvit10:09:00

In both cases, the value is not modified

borkdude10:09:48

compare to defining a new atom or mutating the contents of an atom

Yehonathan Sharvit10:09:08

I think that both def and alter-var-root don’t modify the content

borkdude10:09:57

by defining a var you mutate the state of the runtime

borkdude10:09:21

I don’t know the exact implementation of def, it could be that it reuses the old object

borkdude10:09:52

seems to be the case, no?

(def a 1)
(def b #'a)
(identical? (var a) @(var b))
(def a 2)
(identical? (var a) @(var b))

borkdude10:09:40

yes, it’s even in the docstring:

borkdude10:09:44

> Creates and interns a global var with the name of symbol in the current namespace (ns) or locates such a var if it already exists.

borkdude10:09:09

but to come back to mutation: the value that is referred to by the var isn’t mutated, like the value in an atom is not mutated, but replaced. but you could say the var itself is mutated

Yehonathan Sharvit10:09:57

@borkdude did you mean (identical? @(var a) @@(var b))?

lispyclouds10:09:01

yes, i'd like to think of it as changing the value associated by the name. def for me is an explicit naming of a value where as using atoms or alter-var-root gives us a feel of in place mutation regardless of their actual implementations

borkdude11:09:03

@viebel no, I was comparing the var objects, not the thing inside the var objects

borkdude11:09:05

but to make it simple: Clojure has a couple of mutable cell references: vars, atoms, refs and agents. vars are designed to be mutable.

Yehonathan Sharvit11:09:08

Both the vars are identical and the values. The same happen if we do (alter-var-root #'a inc)

borkdude11:09:45

yes, it seems alter-var-root has the same effect as re-deffing

Denis G11:09:42

I have a vector of numbers, like [2,3,5] Need to create a sorted sequence of (distinct, nice to have) it's multiplies (dunno how to express it better) But the result I want is → [2,3,4,5,6,8,9,10,12,14,15, ...] Would like an infinite sequence

henrik11:09:28

@denisgrebennicov

(sort (distinct [1 4 2 3 4 2 5 5]))

=> (1 2 3 4 5)

Denis G11:09:15

but I want the multples, like multiplying iterate with this sequence, take the distinct and sort them

Denis G11:09:56

meaning [2,3,5, 2*2, 2*3, 4*2, 3*3, 2*5, ...]

henrik11:09:57

I’m not sure I understand, what do you mean by multiples?

henrik11:09:51

Do you mean, you want to take [2 3 5] and get all possible multiplications of those numbers?

Denis G11:09:55

@borkdude for me for sure 😄 actually solving this problem: https://www.hackerrank.com/challenges/minimum-time-required/problem?h_l=interview&amp;playlist_slugs%5B%5D=interview-preparation-kit&amp;playlist_slugs%5B%5D=search And was thinking of doing something like this, since this would make solving the problem easier

Denis G11:09:11

> Do you mean, you want to take [2 3 5] and get all possible multiplications of those numbers? exactly. in sorted order, distinct only

borkdude11:09:38

so it’s an x-y problem

Denis G11:09:46

what does this mean? 😄

borkdude11:09:29

but it’s an interesting subpuzzle 😉

Denis G11:09:31

@borkdude but still interested in this, even if this is a wrong approach exactly 😄

Denis G11:09:15

@borkdude so iterate/range and then filter

borkdude11:09:42

I’m not sure what the formal problem is. Each number in this range is the product of either, 2, 3 or 5?

Denis G11:09:55

sounds much more simpler than multiplying then sorting then distinct 😄

borkdude11:09:17

so 7 is not one of those

Denis G11:09:54

all modulos should be zero

borkdude11:09:58

and 8 is, because 2^3. 9 is because 3^3, 10 is because 2*5, etc.

borkdude11:09:38

^ means power

borkdude11:09:21

good luck 😉

Denis G11:09:13

thanks 🙂

henrik11:09:50

… machines that take [2, 3, 2] days to produce an item. I.e., they produce [1/2 1/3 1/2] items per day. So they produce 1 1/3 items per day. Number of items modulo that, right?

Denis G11:09:07

number of items modulo speed what about this e.g. [5 and 10], target is 2, won't your answer be 7.5/8 days or smth since at 8 the first machine will do 0.6 and machine 2 will do 0.8 amount of work

henrik11:09:47

Yep, you’re right. Only whole items count, so that’s a no-go.

henrik11:09:03

(def speed 2)

(def prod (let [xf (comp (map inc)
                         (map #(mod % speed))
                         (map-indexed vector)
                         (filter #(-> % second zero?))
                         (map first))]
            (sequence xf (range))))

(take 10 prod)
=> (1 3 5 7 9 11 13 15 17 19)

henrik11:09:05

Day 1, 3, 5 and so on for speed 2?

Denis G11:09:08

I guess range and filter doesn't sound so good, since machines can be up to 10^9 to go through all of them for every i in range

Denis G11:09:30

what does speed mean?

henrik11:09:03

2 days to produce 1 item.

henrik11:09:41

But seqs are lazy, so drop + take should let you iterate through an arbitrarily long sequence without blowing a giant hole in your memory.

henrik11:09:10

Nah, I’m not sure.

Denis G11:09:52

A guess I can use a priority_queue or smth. Popping the day and multiplier of that day. Then looking at day-machines-map subtracting items to do by the day-machines-map[day] length and then insert the day with new multiplier priority-queue should work on day * multiplier or smth dunno

Denis G11:09:37

This is not really a clojure problem, sorry for spamming. Normally I try to solve problem in Python, then do a Clojure version

borkdude11:09:50

@denisgrebennicov I notice there is also a #puzzles channel. And if you would like, there will probably more activity around puzzles in #adventofcode around December.

metal 4
henrik12:09:44

Drop map first and filter and you get a sequence of vectors where the first item is the day, and the next is number of items produced that day.

(def speed 2)

(def prod (let [xf (comp (map inc)
                         (map #(mod % speed))
                         (map-indexed vector))]
            (sequence xf (range))))

(take 10 prod)
=> ([0 1] [1 0] [2 1] [3 0] [4 1] [5 0] [6 1] [7 0] [8 1] [9 0])
Make three of these for speeds 2, 2, and 3, and you could easily loop over all three, adding the number produced that day until the desired number of items are reached. I think.

Denis G12:09:12

Thanks. But if speed is dynamic array coming at runtime

henrik12:09:55

For lazy sequences, you’re never holding the entire thing in memory at any one time. They are only computed when they are realized. (range) is infinite. But by doing (take 10) I’m only considering 10 of those.

Denis G12:09:08

The problem is about speed being constant in this case and not dynamically set as an array/vector/seq

Yehonathan Sharvit12:09:53

A philosophical question: Is it expected that (= [1 2] '(1 2)) ?

mfikes12:09:56

Probably because it simplifies a lot of code

Yehonathan Sharvit12:09:16

You mean code inside Clojure itself or inside apps written in Clojure?

mfikes12:09:31

Definitely, code written using Clojure

borkdude12:09:02

would be a good one to add to the faq: https://clojure.org/guides/faq

mfikes12:09:03

Likewise, hash intentionally produces the same value

pvillegas1212:09:15

Is there a better way to achieve (assoc response :headers (merge (:headers response) {:a 1 :b 2}) )?

Yehonathan Sharvit12:09:41

@mfikes Indeed it makes sense to consider that (= (map inc [1 2 3]) '[2 3 4]) although (map inc [1 2 3]) is a lazy sequence

borkdude12:09:54

(update response :headers merge {:a 1 :b 2})

👍 4
Denis G12:09:58

@viebel there is identical? when you need the pointer/object reference comparison. But = operator does make sense, since content inside is the same

Yehonathan Sharvit12:09:03

@denisgrebennicov identical? is very dangerous/tricky. For instance (identical? [1] [1]) is false

sundarj12:09:52

that's because they're two different vectors in memory. it's expected

borkdude12:09:43

it works as equality for a small number of lists though 😛

(let [a '()
        b '()]
    (identical? a b))

mfikes12:09:04

The abstract nature of = also applies to numbers

Yehonathan Sharvit12:09:40

What do you mean @mfikes by the abstract nature of =?

alexmiller13:09:49

For collections, there are “equality partitions” - sequentials, sets, and maps.

alexmiller13:09:36

All sequential collections compare = (vectors, lists, sequences)

alexmiller13:09:29

This is essential when working with a mix of collections and sequences

alexmiller13:09:20

After years of reflection on it, I think that equality working over all sequential collections was a brilliant and non-obvious design choice

👍 8
andy.fingerhut15:09:43

I have an article on the main ideas, and a few subtleties, of Clojure's = and hash implementations, here: https://github.com/jafingerhut/thalia/blob/master/doc/other-topics/equality.md

Yehonathan Sharvit07:09:51

@U064X3EF3 can you share some examples of the advantages of this non-obvious design choice? When I teach Clojure to beginners, and show them that (= [1 2] '(1 2)) is true, they find it very surprising. And indeed, when you put it out of any application context, it is surprising. But when you think about in the context of an application, it starts to make sense: you don’t want to find yourself in a situation when [1 2 3] is not equal to (map inc [0 1 2]) just because map returns a lazy sequence. Do you see it the same way?

Yehonathan Sharvit12:09:54

How does it apply to numbers?

mfikes12:09:31

Digging up my copy of Clojure Programming, which has a great section on the subject

Yehonathan Sharvit13:09:22

even == present some surprises:

(not (== (+ 0.1 0.2) 0.3))
(== (+ 0.2 0.3) 0.5)

mfikes13:09:16

Yeah, that’s IEEE 754

mfikes13:09:04

Related to that

(+ 0.1 0.2 0.3)
needs to associate from the left 🙂 It would be incorrect for Clojure or ClojureScript to effectively do
(+ 0.1 (+ 0.2 0.3))

mfikes12:09:45

Oh, right, you need to use ==. Perhaps the docstring for = is incorrect.

quadron13:09:28

how do i express dependent relationships between components of a tuple spec? say I need a tuple of two strings such that the first one has the same characters as the second one

borkdude13:09:11

(let [[a b] ["foo" "bar"] (= a b)) ?

quadron13:09:50

@borkdude I want to express this in spec parlance for tuples

quadron13:09:09

(s/tuple (s/coll-of ::public-key) (s/coll-of ::private-key) ???such that each private key corresponds to a public key??? )

alexmiller13:09:45

You can s/and any arbitrary predicate onto that coll-of spec

👍 4
quadron13:09:12

yes but how do i capture the public-keys in a symbol?

borkdude13:09:43

(s/valid? (s/and (s/tuple string? string?) (fn [[a b]] (= a b))) ["a" "a"])

✔️ 4
borkdude13:09:34

sorry, didn’t read the thing about public key yet

borkdude13:09:02

but should work similarly

quadron13:09:11

huh! I see, thx

henrik15:09:12

@denisgrebennicov This is fun to tinker with! Thanks for the puzzle. It certainly takes time to calculate the production day for a billion items on my poor laptop, but it doesn’t use much memory at all.

idiomancy16:09:01

okay, great, I'll take a look!

val_waeselynck19:09:17

@U250T6MFA table/column or class/method is a good starting point, you'll figure the paterns soon enough, and Datomic gives you enough flexibility to recover from your mistakes

dustingetz14:09:53

@U250T6MFA +1 for table/column. You will be able to figure this out as you go. Just get started.

eraad18:09:00

In addition to table/column, I like to think about the schema as an attribute catalogue that I can use to create entities. So don´t worry about having ALL possible attributes upfront. Just add the minimal attributes your domain needs and follow the best practices https://docs.datomic.com/cloud/best.html#datomic-schema

Denis G15:09:24

@henrik you are welcome hahahah 😄 Obviously time is also very crucial here. (For this kind of hackerrank challenges) But a solution is better than no solution 😉

henrik16:09:45

@denisgrebennicov Yeah, the final reduction can be easily done in parallel I think. I wonder if something like Neanderthal could take care of it.

Denis G17:09:24

@henrik actually the solution to their problem was really "cheap". I didn't expect somethign like this They just do binary search, since they know the input constraints Then for every mid point they compute, they sum all the products that can be done for every machine and check for the goal/items to produce if it is more or less than the given val 😞

👍 4
Denis G17:09:44

but obviously your solution is cool. much more complex though 🙂

Denis G17:09:11

Sample solution:

def minTime(machines, goal):

    machines.sort()

    low_rate = machines[0]
    lower_bound = (goal // (len(machines) / low_rate))
    high_rate = machines[-1]
    upper_bound = (goal // (len(machines) / high_rate)) + 1

    while lower_bound < upper_bound:

        num_days = (lower_bound + upper_bound) // 2
        total = getNumItems(machines, goal, num_days)
        if total >= goal:
            upper_bound = num_days
        else:
            lower_bound = num_days + 1

    return int(lower_bound)


def getNumItems(machines, goal, num_days):

    total = 0

    for machine in machines:
        total += (num_days // machine)

    return total

borkdude16:09:19

reduction in parallel, that reminds me of https://clojure.org/reference/reducers

cristibalan16:09:31

Hi. I am trying to "flatten" an xml tree while adding a depth count to some nodes. I've considered prewalk or xml-sec but it seems they won't help as they use one element at a time. My plan now is to use something like loop [z zipper result []] over an xml-zip to copy nodes out and use (count zip/path) where needed. Is there a more idiomatic approach?

Eccentric J16:09:55

Hello so a coworker has expressed interest in learning programming. I would love to introduce them to Clojure but I’m concerned it might not have a lot of educational content aimed at absolute beginners like Python currently has. Is there any resources that come to mind that would introduce absolute beginners to Clojure?

alexmiller17:09:37

ClojureBridge curriculum maybe?

donaldball17:09:54

Kyle Kingsbury wrote a fine introduction that doesn’t assume any background knowledge a few years back: https://aphyr.com/posts/301-clojure-from-the-ground-up-welcome

Eccentric J17:09:29

Thanks, I’ll look into those!

simon17:09:26

is it possible to start a clojurescript repl in cursive using boot?

simon17:09:02

(defn- generate-lein-project-file! [& {:keys [keep-project] :or {keep-project true}}]
  (require ')
  (let [pfile ((resolve ') "project.clj")
        ; Only works when pom options are set using task-options!
        {:keys [project version]} (:task-options (meta #'boot.task.built-in/pom))
        prop #(when-let [x (get-env %2)] [%1 x])
        head (list* 'defproject (or project 'boot-project) (or version "0.0.0-SNAPSHOT")
               (concat
                 (prop :url :url)
                 (prop :license :license)
                 (prop :description :description)
                 [:dependencies (conj (get-env :dependencies)
                                      ['boot/core "2.6.0" :scope "compile"])
                  :repositories (get-env :repositories)
                  :source-paths (vec (concat (get-env :source-paths)
                                             (get-env :resource-paths)))]))
        proj (pp-str head)]
      (if-not keep-project (.deleteOnExit pfile))
      (spit pfile proj)))

(deftask lein-generate
  "Generate a leiningen `project.clj` file.
   This task generates a leiningen `project.clj` file based on the boot
   environment configuration, including project name and version (generated
   if not present), dependencies, and source paths. Additional keys may be added
   to the generated `project.clj` file by specifying a `:lein` key in the boot
   environment whose value is a map of keys-value pairs to add to `project.clj`."
 []
 (with-pass-thru fs (generate-lein-project-file! :keep-project true)))
I added this snippet from the For Cursive Users section of the boot docs

simon17:09:27

It seems successful for generating a clojure repl. But I can’t figure out how to get it create a clojurescript repl

noisesmith18:09:32

that really depends on the kind of repl you want. Usually it's going to be a piggybacked REPL, where a clojure repl is started, and some function starts a cljs repl on top of that connected to a browser via websocket (this is how figwheel does things for example - the java side code recompiles, and sends to the browser, and the cljs repl operates via a websocket on top of that process)

dangercoder19:09:33

Guys Sente is insanely nice.

dangercoder19:09:06

Anyone tried to run it at a big scale? Thousands of clients

noisesmith20:09:03

what I ended up needing was a "bounce channel" that propagated async results so that the client could still get them if they reconnected and load balanced to a different server

noisesmith20:09:32

I didn't have thousands of clients, but a heavy enough app with enough clients to require multiple servers with load balancing

noisesmith20:09:22

the tl;dr of the design is that for any delayed result, you need a way to get that result to the server that that client is currently talking to (or accept that that flow of data breaks if they find a new server)

dangercoder04:09:34

Thank you for the insight @U051SS2EU 👍

dhruv122:09:20

Is hara.event the conditional restart library no longer supported?

dhruv122:09:31

I cannot even find the documentation for the library.

noisesmith22:09:27

the github appears to have been taken down

noisesmith22:09:10

the author got fed up with clojure at some point (wrote a big blog post about it) and may still feel that way?