Fork me on GitHub
#beginners
<
2017-05-29
>
Drew Verlee00:05:09

This is the first time i have been like, yea, this is way harder in clojure then in python: http://www.4clojure.com/problem/53. The problem is to much about keeping track of state to have a declartive solution that isn’t actual less descriptive then an imperative one.

Drew Verlee00:05:35

The best bet is probably to fall back to just reduce.

Drew Verlee01:05:14

ok if we can turn [[0 1] [1 2] [2 3]] into [0 1 2 3] in an elegant way we can redeem clojure on this one 🙂

Drew Verlee01:05:18

never-mind, even with those changes my function doesn’t work. You need to keep track of to much state for it to be a good fit imo.

noisesmith02:05:08

@drewverlee for things that truly need state across args, that work across an input sequence, I find reduce tends to work nicely

noisesmith02:05:51

that's what I used in my answer to that question (I admit, I answered it a long time ago and I need to re-read to make sure I still think that's the most elegant - but it's not a super complex block of code)

madstap02:05:58

@drewverlee I don't know, I think mfikes's solution was pretty elegant...

noisesmith02:05:45

imho mine is better 😛

Drew Verlee02:05:23

I haven’t seen a solution yet where I (personally) was like yea, thats better then what i would do in an imperative style. But maybe i need to review them more closely 🙂

Drew Verlee02:05:02

@noisesmith whats your handle on 4clojure? if you dont mind me asking

noisesmith02:05:36

some of my answers are crap, but I think my answer for that one is decent

john02:05:31

@drewverlee here's a crack at it:

(fn [y]
  (let [firsts (fn [x] 
                 (map #(subvec x 0 %) 
                      (range (inc (count x)))))
                      ;; [1 2 0] => ([] [1] [1 2] [1 2 0])
        rests (fn [x] 
                (loop [a x acc []] 
                  (if (not (empty? a)) 
                    (recur (rest a) (conj acc a)) 
                    acc)))
                      ;; [1 2 0] => [[1 2 0] (2 0) (0)]
        consecutive? (fn [x] 
                       (every? #(= -1 %) 
                               (map #(apply - %) 
                                    (partition 2 1 x))))
                       ;; [1 2 0] => false
        consecutives (fn [x] 
                       (filter 
                         #(and (consecutive? %) (apply < %)) 
                         (filter #(> (count %) 1) 
                                 (apply concat (map rests (firsts x))))))
                       ;; [1 2 0] => ([1 2])
        longest-consecutive (fn [x] 
                              (vec (last (sort-by count (consecutives x)))))]
                       ;; [1 2 0] => [1 2]
    (longest-consecutive y)))
Can probably be made a lot prettier, but the method is there

Drew Verlee02:05:56

@noisesmith i submit a patch to change = to > so it works over any increase amount. Other then that, yea, thats exactly how i was thinking this should be done. Thanks. What kills my solution is that partition-by cuts a value i need (the last value in the seq). Essentially you end up with a structure where some elements have different meanings and you can’t map and filter your way to victor. Hense reduce :0

noisesmith02:05:27

I could imagine a lazy-seq version built on rests

noisesmith02:05:42

(which iirc is just (iterate rest l))

noisesmith02:05:36

oh man I might have to re-solve this now

john02:05:23

ah, (iterate rest l) I knew it was there lol

john02:05:26

(take (count l) (iterate rest l))

john02:05:48

Could probably do the same on the way forward, with a reverse or two

Drew Verlee02:05:34

I’m just looking at the soultions on 4clojure and the one thing they have in common, is, for the most part, they have nothing in common. Which, i think, is an undesirable trait. As multiple solutions to a problem as it indicates a lack of a clear way to solving the problem. I’m following like 50 random people that all finished 156 questions, maybe i should have been more discerning in my followers though as i do like noises the best at this point.

john02:05:33

Where can you see the other answers?

Drew Verlee02:05:05

@john you follow people then after you solve the problem you can see other solutions.

john02:05:57

probably don't need the (apply < %) above. Yeah, this is a pretty fun one 🙂

noisesmith03:05:01

if 4clojure accepted as-> this would be my new answer:

(defn longest-increasing [l]                                                    
  (let [tails (take-while seq (iterate rest l))                                 
        adj #(= (inc (first %)) (second %))]                                    
    (apply max-key count                                                        
           (map #(-> %                                                          
                     (->> (partition 2 1)                                       
                          (split-with adj))                                     
                     (as-> [a b]                                                
                       (concat a (take 1 b)))                                   
                     (->> (map first)))                                         
                tails))))  

noisesmith03:05:13

it works, and it's all lazy-seq ops instead of imperative

john03:05:11

all that thrushing is slowing me down a bit. But that's pretty pretty

Drew Verlee03:05:48

ill have to take a look at that in the morning thanks though

noisesmith03:05:21

hmm - how about this one (it passes unlike my last silly one)

(fn longest-increasing [l]                                                      
  (letfn [(tails [s] (take-while seq (iterate rest (concat  l [nil]))))         
          (adj [[a b]] (= (inc a) b))                                           
          (these-and-1 [[a b]] (concat a (take 1 b)))                           
          (take-run [nums]                                                      
            (->> nums                                                           
                 (partition 2 1)                                                
                 (split-with adj)                                               
                 (these-and-1)                                                  
                 (map first)))                                                  
          (lonely [l] (= 1 (count l)))]                                         
    (apply max-key count                                                        
      (->> (tails l)                                                            
           (map take-run)                                                       
           (cons [])                                                            
           (remove lonely))))) 

noisesmith03:05:29

it's less concise, but may be more clear

john03:05:32

yeah, that's pretty awesome

john03:05:44

Here's a version with some transducing:

(fn longest-increasing [x]
  (let [rests (fn [y] (take (count y) (iterate rest y)))]

    (vec
      (last
        (sort-by count

                 (filter (fn [y] (and (> (count y) 1) 
                                      (every? #(= -1 %) 
                                              (map #(apply - %) (partition 2 1 y)))))

                         (into []

                               (comp 
                                 (map reverse) 
                                 (mapcat rests) 
                                 (map reverse))

                               (rests x))))))))

noisesmith03:05:35

couldn't the filter be inside the comp of the transducer?

john03:05:13

not naively, at least

noisesmith03:05:24

I don't get it

noisesmith03:05:29

it would just be the last thing in the comp

john03:05:47

Ah, I tried first. one sec

john03:05:34

(fn longest-increasing [x]
  (let [rests (fn [y] (take (count y) (iterate rest y)))]

    (vec
      (last
        (sort-by count
                 (into []

                       (comp
                         (map reverse)
                         (mapcat rests)
                         (map reverse)
                         (filter (fn [y] 
                                   (and (> (count y) 1)
                                        (every? #(= -1 %)                                                 
                                                (map #(apply - %) 
                                                     (partition 2 1 y)))))))
                       (rests x)))))))

dpsutton03:05:34

and they say lisps are unreadable

noisesmith03:05:18

(vec
      (last
        (sort-by count
can be replaced with (apply max-key count (plus removing a couple close parens at the end)

noisesmith03:05:34

equality doesn't care about vec vs. lazyseq

john03:05:06

wasn't tracking max-key

john03:05:15

ay caramba lol

noisesmith03:05:21

+user=> (doc max-key)
-------------------------
clojure.core/max-key
([k x] [k x y] [k x y & more])
  Returns the x for which (k x), a number, is greatest.
nil

noisesmith03:05:17

so (max-key count a b c) calls count on each of a,b,c and returns the one for which count had the largest result

john03:05:55

(fn longest-increasing [x]

  (let [rests #(take (count %) (iterate rest %))]

    (->> (rests x)

         (sequence

           (comp

             (map reverse)

             (mapcat rests)

             (map reverse)

             (filter #(every? #{-1} (map (partial apply -) (partition 2 1 %))))

             (map #(if (< 1 (count %)) (vec %) []))))

         (apply max-key count))))

john03:05:13

map-key was pretty new to me, but the rest seems pretty idiomatic.

noisesmith03:05:33

wouldn't that miss increasing subsequences in the middle of a collection?

john03:05:35

Not lazy, like yours

noisesmith03:05:03

well, the max-key on the outer level means the whole thing can't be lazy, even if individual things inside can be

noisesmith03:05:23

it's a non-lazy question by definition "thing that is largest by this score"

john03:05:37

handles this fine: (longest-increasing [1 0 1 2 3 0 4 5]) => [0 1 2 3]

noisesmith03:05:53

oh right because of how you use rests

noisesmith03:05:33

the vec call doesn't do anything in the context of this question btw

john03:05:37

updated the last example. Spammed the channel enough 🙂

gmercer13:05:34

Is it possible for the reader to lazily eval regex? The following breaks in clj and cljs but each regex is valid in it's own lang `(def reggy #?(:clj #"(?s)http://HAT.CAT" :cljs #"BAT\0MAN"))`

gmercer13:05:24

(def reggy #?(:clj #"(?s)"
              :cljs #"BAT\0MAN"))

gmercer13:05:56

@cgrand or is this another for your collection of oddities

cgrand13:05:44

@gmercer not an oddity, definitely a pitfall of reader conditionals: all branches are read so each branch must be readable even if not runnable.

cgrand13:05:36

(def reggy (re-pattern #?(:clj ... :cljs ...))) instead

gmercer13:05:38

I need a better example on the cljs side .. where java can handle the string but not the regex 😉 Thanks - that provides the "laziness" I need

dpsutton14:05:02

which case is the error?

dpsutton14:05:13

i thought this is what it was supposed to look like?

john14:05:04

Does it matter they type of the returning collections?

(defn rotate [s]
  (cons s (map concat (rest (rests s)) (reverse (rest (map reverse (rests (reverse s))))))))

john14:05:27

(loving these rests recently :))

john14:05:17

Ooops,

(defn rests [x] (take (count x) (iterate rest x)))

john14:05:22

You need that too

dpsutton14:05:44

yeah i've been using iterate, repeat, cycle a bit recently

john14:05:29

Here's another with the rests built in:

(defn rotations [s]
  (-> (mapcat
        (rest (take (count s) (iterate rest s)))
        (reverse (rest (map reverse (take (count s) (iterate rest (reverse s)))))))
    (cons s)))

john14:05:08

Came up with a cleaner version of problem 53 transducer solution:

(fn longest-increasing [number-sequence]

  "Finds the longest subsequence of consecutively increasing numbers."

  (let [longest     #(apply max-key count %)
        increasing? #(every? #{-1} (map (partial apply -) (partition 2 1 %)))
        long-enough #(if (< 1 (count %)) (vec %) [])
        rests       #(take (count %) (iterate rest %))

        exploder    (comp (map reverse) (mapcat rests) (map reverse))
        increasers  (comp exploder (filter increasing?) (map long-enough))

        increasing  #(sequence increasers (rests %))]

    (-> number-sequence (increasing) (longest))))

john14:05:59

Which is more performant. But 4clojure doesn't recognize transducers yet, so you can do this instead:

(fn longest-increasing [number-sequence]

  (let [longest     #(apply max-key count %)
        increasing? #(every? #{-1} (map (partial apply -) (partition 2 1 %)))
        long-enough #(if (< 1 (count %)) (vec %) [])
        rests       #(take (count %) (iterate rest %))

        exploder    #(->> % (map reverse) (mapcat rests) (map reverse))
        increasers  #(->> % (exploder) (filter increasing?) (map long-enough))
        increasing  #(-> (rests %) increasers)]

    (-> number-sequence (increasing) (longest))))

john14:05:49

Nicely self-documenting. But if you're more into terse:

(fn longest-increasing [x]
  (->> (take (count x) (iterate rest x))
       (map reverse)
       (mapcat #(take (count %) (iterate rest %)))
       (map reverse)
       (filter #(every? #{-1} (map (partial apply -) (partition 2 1 %))))
       (map #(if (< 1 (count %)) (vec %) []))
       (apply max-key count)))

john14:05:49

@vitruvia but looking at your code, (cons rotated (rotations rotated))seems to pass rotated back into the top-level function, but rots is never passed back in.

john14:05:10

Usually, when using that method, (cons rotated (rotations rotated)) would be in the tail position, so the results of the recursion are actually chained together.

vitruvia15:05:49

the error is that I get a StackOverflowError: Null

noisesmith16:05:47

when something is recursive and you get a stack overflow, that means your stop condition isn't being hit

vitruvia16:05:53

I'm not sure what you mean @john . Rots is meant to get called unless the rotation count is the same as the number of elements in the sequence

john16:05:05

@vitruvia Try to imagine what the value of rotated in rotated (concat (rest a-seq) (vector (first a-seq)) will be on the second iteration, where only the rest of rotated is passed in.

vitruvia16:05:07

rots is meant to concatenate all the rotation, so (count rots) should return the number of all rotations so far, no? Then if it is equal to (count a-seq) it should stop

vitruvia16:05:25

ok just a second

vitruvia16:05:44

@john I don't see the mistake. On the recursive call I am sending the whole of rotated, not just the rest

john16:05:35

@vitruvia Yeah, I totally misread that.

vitruvia16:05:15

but @noisesmith does seem to be right on that the termination condition is not being reached

vitruvia16:05:56

maybe (count rots) doesn't return what I think it does? I don't know how to debug on clojure or I would check it

dpsutton16:05:36

what text editor / IDE are you using?

dpsutton16:05:34

ah no idea. sorry

john16:05:56

You can always sprinkle println's, but I'm not sure if they'll print in this case.

john16:05:33

@vitruvia nevertheless, in (= (count a-seq) (count rots)), you're treating a-seq as if it is still the original size of a-seq. I'm not sure how that's going to be possible, if you're passing in a new rotated each time. rots and a-seq may never line up.

john16:05:54

and with (if (empty? a-seq) (sequence a-seq) ... if a-seq is empty, sequence would return nil.

john16:05:41

It looks like you're using a-seq as an accumulator and a remainder at the same time.

john16:05:05

@vitruvia this might be the ticket:

(defn rotations [a-seq]
  (if (= (count (first a-seq)) (count a-seq))
    (sequence a-seq)
    (rotations (concat (rest a-seq) (vector (first a-seq))))))

vitruvia16:05:28

The test case required that if the sequence is empty it returns (). That is the only way I found of doing that (worked on other functions). Also I don't see the problem in presuming that a-seq has the same length of the previous, since rotated always keeps the length intact.

john16:05:15

Ah, I see

vitruvia16:05:21

Sorry your version gets an error. I think (count (first a-seq)) isn't supported

vitruvia16:05:47

Here are a few test cases

(rotations [])        ;=> (())
(rotations [1 2 3])   ;=> ((1 2 3) (2 3 1) (3 1 2))
(rotations [:a :b])   ;=> ((:a :b) (:b :a))
; The order of rotations does not matter.
(rotations [:a :b])   ;=> ((:b :a) (:a :b))
(rotations [1 5 9 2]) ;=> ((1 5 9 2) (2 1 5 9) (9 2 1 5) (5 9 2 1))
(count (rotations [6 5 8 9 2])) ;=> 5

vitruvia16:05:58

After the arrow is the intended result

john16:05:17

When you say, "gets an error," do you mean you're getting an error at the repl?

john16:05:34

ah, geez, sorry, typo in my repl

vitruvia16:05:40

@john yes an error in the repl

john17:05:17

@vitruvia this might work

(defn rotations [a-seq]
  (if-not (coll? (first a-seq))
    (rotations [a-seq (vec (concat (rest a-seq) (vector (first a-seq))))])
    (if (= (count (first a-seq)) (count a-seq))
      a-seq
      (rotations (conj a-seq (#(vec (concat (rest %) (vector (first %)))) (last a-seq)))))))

john17:05:34

returns all vectors

john17:05:26

@vitruvia Here's a version that returns lists:

(defn rotations [a-seq]
  (if-not (coll? (first a-seq))
    (rotations [a-seq (concat (rest a-seq) (list (first a-seq)))])
    (if (= (count (first a-seq)) (count a-seq))
      (apply map list a-seq)
      (rotations (conj a-seq (#(concat (rest %) (list (first %))) (last a-seq)))))))

vitruvia17:05:44

was commuting let me check

john17:05:22

I like this version better though:

(defn rotations [s]
  (->> (map concat
            (rest (take (count s) (iterate rest s)))
            (reverse (rest (map reverse (take (count s) (iterate rest (reverse s)))))))
       (apply map list (concat s))))

vitruvia17:05:47

yes the second version works for the empty case, too. The first doesn't

vitruvia17:05:54

could you find exactly what I was doing wrong though?

john17:05:15

@vitruvia this version is more explicit:

(defn rotations [s]
  "Provides all rotations of a sequence."
  (let [rests       #(take (count %) (iterate rest %))
        other-halfs #(reverse (rest (map reverse (rests (reverse %)))))
        whole-thing #(apply map list (concat %))]
    (->> (map concat (rest (rests s)) (other-halfs s))
         (whole-thing))))

john17:05:43

@vitruvia you weren't checking if (coll? (first a-seq))

john17:05:19

if the first item in a-seq was a number, then we were on the first iteration. If it was a coll, we were on a subsequent iteration.

john17:05:07

oh I see what you mean about the empty case

john17:05:23

(defn rotations [s]
  "Provides all rotations of a sequence."
  (if (empty? s)
    s
    (let [rests #(take (count %) (iterate rest %))
          other-halfs #(reverse (rest (map reverse (rests (reverse %)))))
          whole-thing #(apply map list (concat %))]
      (->> (map concat (rest (rests s)) (other-halfs s))
           (whole-thing)))))

vitruvia17:05:12

I wasn't checking if a-seq was a coll but I was forcing it to become a coll by (sequence a-seq)

john17:05:24

I don't mean for sequence. Notice how mine had two recursion branches? One for when we initially provide a sequence of numbers. The other for when we provide a sequence of sequences of numbers.

john17:05:28

All iterations subsequent to the first pass in a sequence of sequences, rather than a sequence of numbers we pass in on the first iteration.

vitruvia17:05:17

this is great

vitruvia17:05:32

but it uses functions I haven't learned yet...

vitruvia17:05:40

like iterate and take

john18:05:18

Take is pretty basic. You should def catch up on that one. Very useful. Iterate is a little more advanced.

john18:05:12

And (iterate rest %) is a little fancy

vitruvia18:05:28

I just have read on take, but I think the exercise is meant to be done with the tools given so far =(

vitruvia18:05:36

I'm tempted to read the source code for this

vitruvia18:05:40

but that is like cheating

john18:05:09

You can replace the (iterate rest %) with something like

(fn [x]
  (loop [a x acc []]
    (if (not (empty? a))
      (recur (rest a) (conj acc a))
      acc)))

john18:05:12

Take can probably be written in something else, but I'd be surprised if you weren't allowed to use it.

vitruvia18:05:24

Nah its an online exercise, it is not gonna fail, just trying to see if I can do it with something else

vitruvia18:05:41

but I think that second solution was the best

vitruvia18:05:43

I just need to read up on the functions

vitruvia18:05:47

thanks! 😄

dhruv118:05:57

how can i deploy a standalone jar to a nexus repo using leiningen?

john18:05:51

@vitruvia In real world code, I'd recommend decomposing these kinds of functions into smaller functions, which can be more easily tested:

(defn heads [x] (rest (take (count x) (iterate rest x))))

(defn tails [x] (reverse (map reverse (heads (reverse x)))))

(defn heads-and-tails [x] (map concat (heads x) (tails x)))

(defn rotations [x] (if (empty? x) '(()) (map seq (cons x (heads-and-tails x)))))

(rotations [1 2 3])
;=> ((1 2 3) (2 3 1) (3 1 2))

vitruvia19:05:35

@john yes, that would make it much better to debug indeed

vitruvia19:05:43

I think I could do that for the exercise

lepistane20:05:57

are there any examples of applications made in cljs ?

lepistane20:05:26

android or ios?

john20:05:37

@lepistane lots. For react-native on android/ios: http://cljsrn.org/

lepistane20:05:19

i feel stupid now i saw that site but didnt scroll all the way down

john20:05:40

Here's a list of TodoMVC examples using various CLJS frameworks: https://github.com/gadfly361/cljs-todomvc

lepistane20:05:45

holy moly this means i could write one app

lepistane20:05:15

1 app will kinda work for ios, android and web?

lepistane20:05:10

@john thank you very much.

john20:05:59

Honestly, searching github with "cljs" will get you lots of examples. No prob. Another cool example is the documentation for re-com: http://re-demo.s3-website-ap-southeast-2.amazonaws.com It's more for desktop oriented web-apps. But a pretty complete widget library and lots of good examples that run right in the documentation.

lepistane20:05:35

are there any prerequisites to start going at it?

john20:05:03

for re-com, there are a number of 'considerations' called out in the read-me here: https://github.com/Day8/re-com

lepistane20:05:01

so it depends on framework thank you very much kind sir!

john20:05:22

No prob. Enjoy!

lgessler20:05:31

could somebody explain why it's necessary to have 'var' in this snippet?

(defn -main []
  (jetty/run-jetty
    (-> handler var wrap-nocache wrap-reload)
    {:port 3000
     :join? false}))
the book cryptically says "This is necessary to ensure that the var object containing the current handler function is returned. If we used the handler instead, then the app would only see the original value of the function and changes would not be reflected." but I'm unclear on what the difference is between "the var object" and "the handler"

noisesmith20:05:27

when a function is passed as an argument to another function, redefining the function doens't change the behavior of the other function if it is still running

noisesmith20:05:51

if you use a var as a function, clojure looks up the latest value of the var each time you call it, and uses that

noisesmith20:05:32

a var is a mutable container that belongs to a namespace, and holds whatever value def or defn most recently put in it

lgessler20:05:13

aren't we passing the result of the -> macro to run-jetty, though, which is handler inside two middleware closures?

noisesmith20:05:25

it's the var that holds handler

noisesmith20:05:32

that's what calling var on handler does

noisesmith20:05:36

it replaces it with the var

noisesmith20:05:04

(var f) says "don't look up the value of f, just give me the var containing it"

noisesmith20:05:47

and then that var is passed into two middleware closures

lgessler20:05:40

oh is this var business something we're doing to help wrap-reload do its work?

lgessler20:05:50

i thought the book was saying you need to use var for middleware in general

noisesmith20:05:07

wrap-reload works regardless, but without the var quote you would never use the new definition that wrap-reload generates

lgessler20:05:31

ok got it 🙂 thank you

noisesmith20:05:05

a much more reliable alternative is to clojure.tools.namespace/refresh which actually breaks down each namespace and recreates it, thus deleting old definitions and fixing certain issues regarding multimethods and protocols, but this requires some system for easy reloading of the app state (eg. stuartsierra/component or integrant) so it's typically not a default setup

lilactown21:05:50

I'm using emacs+CIDER+nrepl. I just added some new dependencies. what's the best way to recompile my project?

dpsutton21:05:53

in the repl hit comma

dpsutton21:05:29

it will bring up a menu and you can type restart