Fork me on GitHub
#beginners
<
2018-02-01
>
nulligor02:02:02

hello all, does anyone know of a simple gist that could exemplify one of the methods to keep the main thread running cited here? https://github.com/stuartsierra/component#entry-points-in-production

greglook03:02:43

We do something similar, but the exit promise is injected into the component system itself. This lets us provide an HTTP endpoint on the service to ask for a graceful shutdown.

seancorfield04:02:26

Yup, we also put an exit promise in the component, and have -main wait on it, so we can shut things down gracefully (although we don't currently have a use case for that).

Michael Stokley05:02:56

i'm trying to find common or repeated subsections among lists

Michael Stokley05:02:13

for example, find (1, 2) given the lists (1,2,3) and (1,2)

Michael Stokley05:02:20

i can think of a nested imperative way

Michael Stokley05:02:06

for m in l1:
    for n in l2:
        if n == m:
            # continue checking consecutive elements along both lists

Michael Stokley05:02:12

is there a declarative way?

Michael Stokley05:02:19

can anyone point me in the right direction?

andy.fingerhut06:02:39

@michael740 What if the input were the two lists (5, 7, 1, 2, 3, 4, 5) and (9, 11, 1, 2, 9, 1, 2, 3, 6). Should it return (1, 2, 3), because it is the longest common subsequence, even though it doesn't start at the beginning of the lists?

andy.fingerhut06:02:39

And should the common sections be consecutive elements?

seancorfield06:02:54

I remember doing this in APL years ago -- it was easy there 🙂

seancorfield06:02:25

The algorithm was something like build a grid of list A elements equal to list B elements, then rotate each row in the grid by its index, then reduce down the grid to get the (sub) sequences of matching elements... then sort by length (in this case)

seancorfield06:02:10

So for "equality", you'd want to return the element if equal else nil. so for the example above your grid would be

\ 5 7 1 2 3 4 5
9 . . . . . . . 
11 . . . . . . . 
1 . . 1 . . . . 
2 . . . 2 . . .
9 . . . . . . . 
1 . . 1 . . . .
2 . . . 2 . . .
3 . . . . 3 . .
6 . . . . . . . 
and when you rotate the rows, the sequences will line up.

seancorfield06:02:12

The reduce "down" the rotated grid would by (partition-by nil? ...) and then (sort-by count ...) and (last ...)

Michael Stokley07:02:04

wow, that's really sophisticated

seancorfield07:02:57

I think you can (apply map vector ...) to the rotated rows to get columns... so that would be the step between the rotate and the column reduction.

seancorfield07:02:07

And you can rotate the grid by using (take n (drop i (cycle row))) where n is the length of all the rows -- 7 in the case above -- and i in the index in a map-indexed call...

seancorfield07:02:34

(mostly doing this off the top of my head... I should pull up an editor and actually write some code)

Michael Stokley07:02:45

@seancorfield, thank you. i'll puzzle over this tomorrow, after some sleep

Michael Stokley07:02:42

this really is a lot more sophisticated than I would have expected

seancorfield07:02:17

Yeah, here's a REPL session showing what I'm thinking...

boot.user=> (defn rotate [i coll] (take (count coll) (drop i (cycle coll))))
#'boot.user/rotate
boot.user=> (for [x [5 7 1 2 3 4 5]] (for [y [9 11 1 2 9 1 2 3 6]] (when (= x y) x)))
((nil nil nil nil nil nil nil nil nil) (nil nil nil nil nil nil nil nil nil) (nil nil 1 nil nil 1 nil nil nil) (nil nil nil 2 nil nil 2 nil nil) (nil nil nil nil nil nil nil 3 nil) (nil nil nil nil nil nil nil nil nil) (nil nil nil nil nil nil nil nil nil))
boot.user=> (map-indexed rotate *1)
((nil nil nil nil nil nil nil nil nil) (nil nil nil nil nil nil nil nil nil) (1 nil nil 1 nil nil nil nil nil) (2 nil nil 2 nil nil nil nil nil) (nil nil nil 3 nil nil nil nil nil) (nil nil nil nil nil nil nil nil nil) (nil nil nil nil nil nil nil nil nil))
boot.user=> (apply map vector *1)
([nil nil 1 2 nil nil nil] [nil nil nil nil nil nil nil] [nil nil nil nil nil nil nil] [nil nil 1 2 3 nil nil] [nil nil nil nil nil nil nil] [nil nil nil nil nil nil nil] [nil nil nil nil nil nil nil] [nil nil nil nil nil nil nil] [nil nil nil nil nil nil nil])
boot.user=> (map (partial partition-by nil?) *1)
(((nil nil) (1 2) (nil nil nil)) ((nil nil nil nil nil nil nil)) ((nil nil nil nil nil nil nil)) ((nil nil) (1 2 3) (nil nil)) ((nil nil nil nil nil nil nil)) ((nil nil nil nil nil nil nil)) ((nil nil nil nil nil nil nil)) ((nil nil nil nil nil nil nil)) ((nil nil nil nil nil nil nil)))
boot.user=> (map (partial filter (partial every? some?)) *1)
(((1 2)) () () ((1 2 3)) () () () () ())
boot.user=> (mapcat (partial filter (partial every? some?)) *2)
((1 2) (1 2 3))
boot.user=> (sort-by count *1)
((1 2) (1 2 3))
boot.user=> (last *1)
(1 2 3)
boot.user=>

seancorfield07:02:51

I'm off to bed too @michael740 -- my beer's all gone 🙂 Let me know tomorrow what you think!

ackerleytng08:02:36

why does (apply = true '(true true)) work to ensure that all elements of the list are true?

ackerleytng08:02:26

I thought the apply would effectively be (= true '(true true)), which isn't true

flowthing08:02:17

With that arity, applycalls list*: (list* = true '(true true)) ;;=> (#object[clojure.core$_EQ_ 0x601daba4 "clojure.core$_EQ_@601daba4"] true true true)

joelsanchez08:02:41

apply will always apply the last argument as a list, and keep the other arguments

ackerleytng08:02:11

I see, so it is actually (= true true true), which is true

joelsanchez08:02:13

(apply + 1 1 1 [1 1 1]) => (+ 1 1 1 1 1 1)

timo09:02:25

Hi there, I am trying to use environment-variables in clojurescript. I am using luminus with cprop and need the url for the requests to change in dev and prod. How do you do that?

joelsanchez09:02:05

I would probably just store the environment variables in a global object using https://github.com/arohner/scriptjure

joelsanchez09:02:15

you simply output them in your index.html

joelsanchez09:02:35

alternatively, if you don't need this to be dynamic, use goog defines in cljsbuild definition

joelsanchez09:02:15

for example you could have different :closure-defines in the dev cljsbuild and the prod one, or use System/getenv to fetch the values from the environment

timo09:02:14

alright thanks! I'll try that

placeboza10:02:36

Any suggestions on where a noob can start WRT a template/library for making a desktop UI - looking at Gonzih's cljs-electron ATM ?

placeboza10:02:36

Leaning towards an Electron implementation with ClojureScript and Clojure backend

ackerleytng11:02:02

i started with descjop, didn't get too far

ackerleytng11:02:08

still working on it

placeboza12:02:48

@ackerleytng I see that descjop hasn't seen a commit in about a year IIRC - the dev must have moved on or is too busy now.

timo14:02:50

hey guys, is bootstrap the right decision? anyone prefers something else? I dislike loading 300kb with jquery and fontawesome? I thought actually that cljs only takes the required parts but my luminus-app loads all of it. Any suggestions?

timo14:02:32

I mean, what I thought is that the google-closure-compiler only takes the necessary parts of the js-files and leaves the other stuff out? but this is not the case right?

manutter5114:02:22

I use the bootstrap css files but not the js stuff. That's partly because I'm using re-frame, and it's easier for me to let cljs handle all the actions.

timo14:02:39

right, that makes sense

timo14:02:58

then I could leave jquery behind as well

rcustodio17:02:06

hi, https://clojure.org/guides/deps_and_cli about this, we won’t need lein or boot?

bellis19:02:47

for some workflows, yes. there's a channel for it: #tools-deps

Michael Stokley17:02:07

i'm trying to write a nested (loop (recur but having trouble passing some return value from inner loop to outer loop

bronsa17:02:34

you can’t recur or break to an outer loop

bronsa17:02:48

recur is local to the current loop

Michael Stokley17:02:30

bronsa, that's ok, as far as i can tell. i'll wait for the inner loop to finish, move to next iteration of outer loop

Michael Stokley17:02:14

it's basically (for [x (range 3) y (range 5)] (+ x y))

Michael Stokley17:02:00

but i need more fine grained control over which values of x and y i recur with

bronsa17:02:28

you can do (loop [a ..] (let [ret (loop [b ..] ..)] ..))

bronsa17:02:00

but unless you give more info we can’t help much

Michael Stokley17:02:10

let, that does it

bronsa17:02:01

remember that in clojure everything has is an expression, there’s no statements in clojure

bronsa17:02:11

so you can let everything

Michael Stokley17:02:28

is it idiomatic to put a complex expression in the let bindings like that?

bronsa17:02:11

altho if it becomes too big you might want to factor that out into its own function

Michael Stokley17:02:26

(loop [x 0
       outer-acc '()]
  (if (> 5 x)
    (let [inner-ret
          (loop [y 0
                 inner-acc '()]
            (if (> 3 y)
              (recur (inc y) (cons (vector x y) inner-acc))
              inner-acc))]
      (recur (inc x) (concat inner-ret outer-acc)))
    outer-acc))

bronsa17:02:27

that’s not bad, altho there’s no point in using loop here when for would do

Michael Stokley17:02:39

i'm going to have more complex logic over what to pass to recur eventually

bronsa17:02:01

in that case that’s not bad code, if you really need loop

bronsa17:02:33

usually you can express those algorithms using either for or map/`reduce`

Michael Stokley17:02:47

i'd prefer to use for or map/reduce if possible, but i don't know how yet.

petterik21:02:35

This produces the same output

(->> (range 5) 
     (mapcat #(map vector (repeat %) (range 3)))
     (reverse))

Michael Stokley21:02:17

that makes sense.

Michael Stokley21:02:38

but i'm looking for a way to have more dynamic control over the elements in both the inner and the outer loop, as i iterate

Michael Stokley21:02:02

the example i originally gave doesn't really express that, unfortunately...

Michael Stokley17:02:40

i want to jump forward n iterations in the outer loop depending on the result of some inner expression with x and y

Michael Stokley17:02:48

imperatively, this is dead simple

Michael Stokley17:02:26

def compare_lists(l1, l2):
    out = []
    inner_list, outer_list = sorted([l1, l2], key=len)
    i = 0
    while i < len(outer_list) - 1:
        j = 0
        while j < len(inner_list) - 1:
            if outer_list[i] == inner_list[j]:
                shared_sequence = find_shared_sequence(outer_list[i:],
                                                       inner_list[j:])
                if len(shared_sequence) >= MIN_PHRASE_LENGTH:
                    i += len(shared_sequence)
                    out.append(shared_sequence)
            j += 1
        i += 1
    return out

Michael Stokley17:02:08

actually, you were saying i can't recur to an outer loop... maybe that's what this is trying to do

noisesmith21:02:26

this is possible by inverting the logic - instead of passing the args to the outer loop, you return a collection and the outer loop can then construct a recur call. Or, you can use trampoline and letfn, so that each "loop" becomes a function call that returns an anonymous function that invokes the apropriate body (inner or outer), or the final value

Michael Stokley21:02:24

wow, ok. thank you for the response

Michael Stokley21:02:09

at what point would you say to yourself, gosh, the imperative code i'm now trying to express functionally/declaratively is simple enough and maybe i'm not gaining much expressiveness when i have to go to such lengths?

Michael Stokley21:02:27

i suppose that varies person to person

noisesmith23:02:37

it really does improve things to use basic collection ops when traversing a collection (for example)

noisesmith23:02:18

usually my first step is to consider whether the imperative thing I think I want to do can be expressed via a built in traversal with a higher order function

joelsanchez19:02:22

afaik you can't do destructuring in a if-let

joelsanchez19:02:29

well, you can but it's not what you expect

ghadi19:02:59

@yvendruscolo if-let uses the right hand side to determine the success of the test, not the left-side binding

ghadi19:02:23

mymap is truthy, so this succeeds

JJ22:02:12

is it safe to :reload a ns if I haven't done a require on it before?

Michael Stokley23:02:38

i run into this all the time - (map fn collection) throws arityException because fn takes 2+ args and each element in collection is another collection

Michael Stokley23:02:49

solution is to use apply, i think?

noisesmith23:02:37

@michael740 sounds like you want (partial apply fn) in this case

noisesmith23:02:59

if you want each item in the coll to be an arg that is

Michael Stokley23:02:39

(map #(* %1 %2) (list [1 2] [3 4]))

Michael Stokley23:02:58

(map (apply fn) coll)?

noisesmith23:02:05

yeah , change that to (partial apply *) or the equivalent #(apply + %)

noisesmith23:02:28

(apply fn) will error because apply needs a collection

Michael Stokley23:02:44

this is horrible

Michael Stokley23:02:55

should i not be in this position in the first place?

Michael Stokley23:02:13

i have a list of arg-collections i want to feed into a function, one by one

Michael Stokley23:02:18

this seems too convoluted

Michael Stokley23:02:25

maybe i should transform my collection of args [[a1 a2] [b1 b2]] into [[a1 b1] [a2 b2]] and then map over that with implicit zipping

noisesmith23:02:33

did you try the functions I suggested? they work

noisesmith23:02:02

oh, wait, with args like that use (apply map * coll)

noisesmith23:02:25

@michael740 you might notice one is the flipped version of the other

Michael Stokley23:02:27

my collection is currently in the second form