Fork me on GitHub
#beginners
<
2017-02-06
>
bones02:02:55

Is there a cycle-like function where I can hand it a collection of, say, keywords, and returns a function that each time I call it, returns the next item in the collection, cycling back to the start when it reaches the end of my collection?

bones02:02:21

Or is this something I’d have to write myself?

rads02:02:42

@bones: what about cycle?

bones02:02:44

So, cycle DOES give me the sequence, but i cannot retrieve a single value from that, that will alternate with each call

bones02:02:42

e.g. (take 3 (cycle [:a :b]))

bones02:02:55

will give me :a :b :a

rads02:02:03

what output are you trying to get?

bones02:02:30

Whereas I want to be able to do something more like (def cycle-sequence (cycle [:a :b])) (take 1 cycle-sequence) => :a (take 1 cycle-sequence) => 😛

bones02:02:42

ha ha i mean 😛

rads02:02:48

do you need it to be stateful?

rads02:02:31

(take 1 cycle-sequence) should return :a each time

bones02:02:34

Yeah, pretty much

rads02:02:48

(nth cycle-sequence 0) and (nth cycle-sequence 1) would work

bones02:02:21

But i guess I need to keep track of what i last returned

rads02:02:06

it might be easier for me to help with a little more context on what you're trying to do

bones02:02:15

Oh, I was just mucking around with core.async and UI - trying to make a toggle component - instead of merging 2 channels that produced :open and :close messages, I could have a single channel that alternated between the two messages

bones02:02:28

(ultimately passing this fn to map to create a transducer for the chan to always spit out either of these 2 messages)

rads03:02:52

something like this?

(defn toggle-chan []
  (let [ch (async/chan)
        coll (cycle [:open :close])]
    (async/onto-chan ch coll)
    ch))

rads03:02:20

user=> (async/take! (async/into [] (async/take 5 (toggle-chan))) println)
nil
[:open :close :open :close :open]

bones03:02:30

I wonder if that lets me do something like (def c (toggle-chan)) (<! c) open (<! c) close

bones03:02:54

That’s ideally what I want

rads03:02:05

yep, that will work

bones03:02:19

Cheers, I’ll fire up a repl and try

rads03:02:34

good luck 🙂

bones03:02:13

Thanks for your help

rads03:02:23

no problem

roelof06:02:53

I use spec and I use this to say there is a problem.

(throw (Exception. "Something wrong with the detail-page"))  

roelof06:02:13

can I change it so explain is used so I can see what is wrong

bones07:02:28

Using this `(defn cycle-chan [coll] (let [c (chan) idx 0] (go (loop [token (nth coll idx)] (>! c token) (recur (nth coll (mod (inc idx) (count coll)))))) c))`

bones07:02:00

I make a channel (def c (cycle-chan [:a :b]))

bones07:02:34

when i consume the values they should be the sequence :a :b :a :b … but it’s actually :a :b :b :b :b … any idea?

rauh07:02:08

you never inc your idx

rauh07:02:27

Why not use cycle?

bones07:02:29

I did in recur did i not?

bones07:02:41

Cause cycle I have to “realise” the sequence all at once

bones07:02:56

I want to get the cycle one at a time

rauh07:02:58

Your recur goes to the loop, which only defines token

rauh07:02:15

cycle is lazy, it won't realize all at once

bones07:02:47

Yeah but if i (take 1 (cycle [:a :b])) I’ll always get :a

rauh07:02:14

Also your implementation will spin 100% CPU for any unblocking buffer

bones07:02:17

When I want to read a chan/coll and an cycle of the list I originally spplied

rauh07:02:42

What was wrong with the above implementation of rads?

bones07:02:00

It gives me the entire sequence at once

bones07:02:20

I’d like to get one at a time

rauh07:02:09

It will put one after the other as long as you have a bocking buffer

bones07:02:57

Anyway thanks, back to the drawing board

rauh07:02:16

@bones The above onto-chan impl is good, I'd use that

rauh07:02:30

What's your problem with it?

roelof07:02:33

I have found out that a key can be a collection or a string. Can this spec then work

(s/def ::principalMaker (s/or (s/coll-of (s/keys :req-un [::name] ):min-count 1 :max-count 1)) string?)  

beppu08:02:09

@bones:

(require '[clojure.core.async :as a :refer [<! <!! >! >!! chan onto-chan go go-loop]])
(def c (chan))
(onto-chan c (cycle [:a :b]))
(<!! c)
(<!! c)
(<!! c)

roelof08:02:03

How can I tell that something can be a collection or a string in spec ?

roelof08:02:59

and how do I change this to reflect this :

(let [name (-> art-object
                 :principalMaker
                 first
                 :name

bones10:02:10

@beppu primo! Good work, that's just what I meant

beppu10:02:34

@bones np. enjoy.

bones10:02:11

All my trials of using cycle just keep popping :a

beppu10:02:08

Before I knew about onto-chan, I had a version that used a go-loop with cycle. I deleted the message, but the code is sitll in the slack sidebar under Files.

bones10:02:56

Yeah, I thought It could just use something like (take 1 (cycle [:a :b])) but that always gives me :a

bones10:02:32

Do you understand why cycle works as intended in your example and not mine? What am i not understanding?

beppu10:02:48

Yes, I do. The go-loop starts with (cycle [:a :b]) and on the next iteration, it recurs with (next (cycle [:a :b])) so each iteration moves 1 step through the cycle.

bones10:02:49

Oh you’re referring to the example you didn’t post?

beppu10:02:50

they do very similar things. the go-loop i wrote simulates what onto-chan does.

beppu10:02:02

not exactly, but close.

beppu10:02:42

When you guys started talking about core.async, I thought you guys figured it out, so I deleted my message.

beppu10:02:57

I came back a few hours later, and it didn't look quite solved, so I chimed in again.

beppu10:02:54

(go-loop [s (cycle [:a :b])]            ; initial value (cycle [:a :b])
  (>! c (take 1 s))
  (recur (next s)))                     ; next value (next (cycle [:a :b]))

bones10:02:42

It looks as though the onto-chan solution works more idiomatically because you’re passing the cycle to the function, not messing about with take like I did

beppu10:02:00

I prefer the onto-chan solution, because it's more clear what your intent is.

bones10:02:46

Yeah, I should have realised that cycle returns a collection, which will have implemented the ISeqable protocol meaning I can call next to get through it which is what onto-chan does

beppu10:02:48

@bones Here's another way to do it using atoms.

(defn iterator-fn
  ""
  [series]
  (let [s (atom series)]
    (fn []
      (let [v (take 1 @s)]
        (swap! s next)
        (first v)))))
Usage:
(def i (iterator-fn (cycle [:a :b])))
(i)
(i)
(i)

beppu10:02:37

Languages like Perl, Ruby, JavaScript, etc that have closures and use mutation would take this kind of approach.

tbaldridge14:02:31

@bones but realize that most of these functions are introducing impure semantics. i.e. if you call a function with the same args twice and it returns different values, you have an impure function.

tbaldridge14:02:35

So I would consider restructuring your code in such a way that you can do something like (next (cycle [:a :b])) and walk the seq as needed. Functional impurity isn't "wrong" per-se but there's often a better way.

roelof16:02:44

I do the clojure koans another time.

roelof16:02:11

Now the comments say to do

(javadoc "warfare")  

roelof16:02:43

but when I do that I see this message :

CompilerException java.lang.RuntimeException: Unable to resolve symbol: javadoc in this context, compiling:(C:\Users\rwobb\AppData\Local\Temp\form-init3193066558729895878.clj:1:5) 
`

roelof16:02:34

What is the best middleware to postgresql ?

val_waeselynck16:02:08

@roelof (require '[clojure.java.javadoc :refer [javadoc])

roelof16:02:46

@val_waeselynck thanks , there is a typo but I got it working

rads17:02:15

many people use clojure.java.jdbc directly, but there are some DSLs listed here: https://github.com/clojure/java.jdbc

rads17:02:00

clojure makes it easy to work with SQL directly

rads17:02:54

I recommend adding some kind of polymorphism to your external data access functions, i.e. using a multimethod or a protocol. this makes it easier to stub out the DB for testing

shaun-mahood17:02:49

I have an ordered sequence where, for each element n, I want to check it against elements n-1 and n+1. Is there an idiomatic way to do this in Clojure?

roelof17:02:22

@rads : that looks very difficult. IM thinking of using korma or honeysql

rads17:02:29

@shaun-mahood:

cljs.user=> (def s (iterate inc 0))
#'cljs.user/s
cljs.user=> (take 5 (map #(vector %1 %2 %3) s (drop 1 s) (drop 2 s)))
([0 1 2] [1 2 3] [2 3 4] [3 4 5] [4 5 6])

shaun-mahood17:02:40

@rads Awesome, thanks!

schmee17:02:47

@shaun-mahood

user=> (partition 3 1 (range))  
((0 1 2) (1 2 3) (2 3 4) (3 4 5) (4 5 6) (5 6 7)…)

rads17:02:10

nice! that's even better

roelof17:02:58

what is wrong here :

(group-by count ["hello" "world" "foo" "bar"])
CompilerException java.lang.RuntimeException: Unable to resolve symbol: group-by in this  

schmee18:02:17

roelof what namespace are you in?

roelof18:02:05

I think no namespace. I fired up a repl in cursive and begin typing

roelof18:02:05

but also when Im doing this . I see the error :

(in-ns 'koans.22-group-by)
=> #object[clojure.lang.Namespace 0x18682d3 "koans.22-group-by"]
(group-by count ["hello" "world" "foo" "bar"])
CompilerException java.lang.RuntimeException: Unable to resolve symbol: group-by in this context, compiling:(C:\Users\rwobb\AppData\Local\Temp\form-init8140862184290506834.clj:1:1) 

schmee18:02:38

try using ns instead of in-ns

schmee18:02:08

in-ns doesn’t refer clojure.core

roelof18:02:42

then I see this :

(ns 'koans.22-group-by)
ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.Symbol  clojure.lang.RT$1.invoke (RT.java:239)
 

roelof18:02:23

solved :

(ns koans.22-group-by)
=> nil
(group-by count ["hello" "world" "foo" "bar"])
=> {5 ["hello" "world"], 3 ["foo" "bar"]} 

roelof18:02:02

now time for the dishes 😞

shaun-mahood18:02:48

@schmee: Thanks!

roelof19:02:22

Can someone give me a hint what is the answer to the last challenge :

(ns koans.23-meta
  (:require [koan-engine.core :refer :all]))

(def giants
  (with-meta 'Giants
    {:league "National League"}))

(meditations
  "Some objects can be tagged using the with-meta function"
  (=  {:league "National League"} (meta giants))

  "Or more succinctly with a reader macro"
  (=  {:division "West"} (meta '^{:division "West"} Giants))

  "While others can't"
  (=  "This doesn't implement the IObj interface" (try
                                                   (with-meta
                                                     2
                                                     {:prime true})
                                                   (catch ClassCastException e
                                                     "This doesn't implement the IObj interface")))

  "Notice when metadata carries over"
  (= {:foo :bar} (meta (merge '^{:foo :bar} {:a 1 :b 2}
                        {:b 3 :c 4})))

  "And when it doesn't"
  (= nil (meta (merge {:a 1 :b 2}
                     '^{:foo :bar} {:b 3 :c 4})))

  "Metadata can be used as a type hint to avoid reflection during runtime"
  (= \C (#(.charAt ^String % 0) "Cast me"))

  "You can directly update an object's metadata"
  (= 8 (let [giants
             (with-meta
               'Giants
               {:world-series-titles (atom 7)})]
         (swap! (:world-series-titles (meta giants)) #(+ 1 %))
         @(:world-series-titles (meta giants))))

  "You can also create a new object from another object with metadata"
  (= {:league "National League" :park "AT&T Park"}
     (meta (vary-meta giants
                      assoc :park "AT&T Park")))

  "But it won't affect behavior like equality"
  (= ___ (vary-meta giants dissoc :league))

roelof19:02:52

I tried "Giants" and {:park "AT&T park" } but both are not the right answer

schmee19:02:07

metadata doesn’t affect equality, so if you modify the metadata of an object it will still equal…?

schmee19:02:54

hard to give a tip without giving it away 😛

roelof19:02:30

then I think the answer will be giants

roelof19:02:46

I tried it in repl and I saw this :

(vary-meta giants dissoc :league)
=> Giants
 

roelof19:02:59

but the test said it's not the right answer

roelof19:02:49

found it. I had to use the quote one more time : 'Giants

bones21:02:26

ah-ha! thanks @tbaldridge I ended up doing just that last night ( stumbling into the (next (cycle [:a :b])) solution )

bones21:02:11

And realised the solution I had in my head was essentially onto-chan proposed by @beppu

bones21:02:27

I realised cycle was returning a collection which I just needed to traverse via next and first

clodeindustrie22:02:20

hi there, just compiled an uberjar for my project (that is basically just dependencies for the moment) and it’s spitting out a 25MB jar, I this normal ?

seancorfield23:02:17

@clodeindustrie Sounds pretty normal, yes.

seancorfield23:02:11

Ours range from 20MB up to 34MB. You’d be surprised at how many dependencies drag in a lot of other dependencies. A few compiled Java libraries underneath that and you’ll soon have several MB.