Fork me on GitHub
#beginners
<
2016-02-01
>
drewverlee00:02:37

thanks @mfikes, Specially, i'm not sure how to get all my futures into a collection that i can deref (have it block tell all threads are finished). I think i tried to this earlier and hit a roadblock.

(def coll [(future (Thread/sleep 10000) (println "done") 100) (future (Thread/sleep 10000) (println "done") 100)])
I'm missing the building block that elegantly gets my functions into such a collection. My imperative brain is coming up with like 20 ways. Typically i transform an existing collection. But in this case i'm not sure how to end up at the above collection. I feel like i'm asking for all the pieces to the puzzle at this point.

mfikes00:02:49

For the problem you are solving, is there a collection of tasks?

mfikes00:02:55

Let me quickly check out the problem definition simple_smile

mfikes00:02:38

Ahh, the function takes the number of quotes to download. In your example it is 5.

mfikes00:02:12

So, for 5 at a high level you know you’ll end up creating 5 futures, and for that appproach you want to put all of them into a single collection.

drewverlee00:02:22

(repeatedly (future...))?

mfikes00:02:23

Think about (for [n (range 5)] n) and how it can be used to produce a sequence of items.

mfikes00:02:44

With the above, you don’t care about n so much, so (for [n (range 5)] (future …)). There are probably cleaner or more-clever approaches, but that would make 5 futures in a collection.

mfikes00:02:55

There’s probably a cleaner way that doesn’t delve into an imperative mess, but I’d at least try something along those lines.

drewverlee00:02:42

gotcha, thanks @mfikes !

mfikes00:02:28

@drewverlee: I suppose there is a parallelization pitfall in that approach in that for is lazy. You really want to kick off futures in parallel.

mfikes00:02:57

@drewverlee: Wrapping it in doall would solve that, but it feels like a hack. Hmm… what’s the clean way to set up n futures eagerly? I’m starting to lean towards recursion.

mfikes00:02:03

@drewverlee: I think I like this better:

(defn make-futures [n]
  (when (pos? n)
   (cons (future) (make-futures (dec n)))))

drewverlee00:02:23

interesting. I was looking through docs trying to see if repeat or dotimes was appropriate. your trying to make sure that the threads are kicked off asap right?

mfikes00:02:44

As long as n isn’t gigantic, that should be cool simple_smile Otherwise, bigger guns like queues and worker pools, agents, etc. sound would be better. simple_smile

mfikes00:02:43

I guess repeat would fail in that it gives you the same future over and over again.

mfikes00:02:05

dotimes is cool. If you went down that road you’d need to somehow save the futures that are generated

mfikes00:02:37

But, yes, you want to kick of the futures. They will be processed in a finite-sized thread pool, but you at least want to get them going.

drewverlee00:02:58

thanks. I'm playing around now. Ill probably put this together in 2 mins in the morning...

krchia03:02:08

is there a preference or difference between (get-in map [:key]) or (:key map) ?

seancorfield03:02:03

In general (:key map) is considered more idiomatic.

seancorfield03:02:48

If you're using a non-keyword, you might see (map key).

seancorfield03:02:26

If you're not sure you have a map, you could use (get map key) which will return nil ... (get 42 13) returns nil. Does that help @krchia ?

krchia03:02:32

yes it does simple_smile thanks

spinningarrow05:02:42

if I use an atom in clojure to hold some state, should I pass it as a parameter to the functions that use it or just it be global? For example, I’m trying to write a simple implementation of Conway’s game of life and wondering which approach I should use to store and access the “current state of the world”

seancorfield05:02:39

If you pass the state of the world, it wouldn't need to be mutable, you'd just pass updated versions everywhere...

seancorfield05:02:08

You'd use global mutable state only if you didn't want to pass it around as an argument / result.

trancehime06:02:52

Can anyone help me wrap my head around this? https://www.refheap.com/107929

seancorfield06:02:26

Which part do you need help with @trancehime ?

trancehime06:02:40

the (doall ...) block which populates the select

trancehime06:02:49

I am confused by it

seancorfield06:02:55

for each of the keys in the orgcomp1 part of the state, it gets the :id / :name values and produces a select option... the one with id 0 is marked as the default

seancorfield06:02:22

each option has metadata providing a key (with the id as value) -- for React.js I assume?

trancehime06:02:28

reagent specifically

seancorfield06:02:52

The metadata is so that React can keep track of the items in the list as I recall (it needs elements of lists to be uniquely annotated so it can track insertions and deletions).

seancorfield06:02:58

Does that help?

trancehime06:02:22

Thanks, just wanted to get some clarification on the (let [{:keys [id name]} (get-in @state [:orgcompl item])] line

trancehime06:02:48

seems :orgcomp1 in the codeblock is part of @state after all.

seancorfield06:02:10

Yes, so (:orgcomp1 @state) refers to a hash map whose keys are the items and so (get-in @state [:orgcomp1 item]) will drill down to the associated value...

seancorfield06:02:35

...which will be a hash map with at least the keys :id and :name...

trancehime06:02:54

in my case, I'm trying to grab from an entire atom instead of a part of it.

seancorfield06:02:30

So instead of (:orgcomp1 @state) you'll just have @state and instead of (get-in @state [:orgcomp1 item]) you'd have (item @state) -- or (get @state item) if you don't know that item is a keyword.

trancehime06:02:57

Hmm okay, so that would be fine? Was scared that I couldn't do it in that way

seancorfield06:02:27

If your whole state is the hash map you want to generate the select from, yes.

trancehime06:02:12

yeah, actually the "state" in question isn't really a state as much as it is a collection of smaller maps I want to use to populate the select box

trancehime07:02:37

ugh... wait. it's a vector of hashmaps. no wonder

spinningarrow08:02:08

@seancorfield: you’re right, that’s a good point. In that case, which option makes more sense? having a global mutable state of the world, or passing an immutable state around?

udit11:02:27

What are the best practices for writing/reading configurations for clojure apps? I am writing the configs to an edn file as of now and reading it at the time of app initialization. What should the breakdown of such an edn file be?

jonahbenton11:02:18

hey @udit i use edn files for configuration. usually they're a map, sometimes a vector, depending on the semantics of configuration (key value vs something order-sensitive)

jonahbenton11:02:12

usually configuration is environment-specific, so i'll have different configuration files for test/dev/prod, etc

udit12:02:22

Hey @jonahbenton. So is it like a map inside a map for different staging environments? Also what happens when the number of configurations that I have to store are way too much? Can I split them across different files? If so what are the guidelines for that?

jonahbenton12:02:09

in terms of environment configuration, usually configuration is specific to environment and sensitive configuration data in one environment should not be visible in other environments. i mean, every situation is different but generically i'd suggest one config file per environment- whatever the definition of environment is in terms of more complex per-environment configuration, or, say component-specific configuration within an environment- like database connection details- yes, good idea to keep those in their own files. a single master config can have keys like :database-config-file the value of which is a path to the database config- which may be EDN or could be a property file

udit12:02:27

Got it. Thanks @jonahbenton simple_smile

xc4meron19:02:23

Hey im looking for some help

djtango19:02:23

Hey all, this is a first post, wondering if someone could help me out (please go easy on me simple_smile ).. I have been building a toy project to familiarise myself with Clojure web development using Lein and Compojure... I have a database with two tables tills and menu_items and I am creating a many-to-many relationship via a till_menu_items join table, but I am seeing strange behaviour: the insert works in the lein repl but not when I host the project on ring. Here is the function in question:

(defn add-till-menu-items
  [params]
  (let [[shop-name address phone menu-item-names menu-item-prices]
         (vals params)
        inserted-till (first (inserted-ids (insert-row :tills
                                                       :shop_name shop-name
                                                       :address   address
                                                       :phone     phone)))
        inserted-menu-items (inserted-ids (map #(insert-row :menu_items
                                                            :name  %1
                                                            :price %2)
                                               menu-item-names
                                               menu-item-prices))]
    (prn (str "inserted-till: " inserted-till))
    (prn (str "doseq inserted-menu-items: " inserted-menu-items))
    (for [menu-item-id inserted-menu-items]
      (insert-row :till_menu_items
                  :till_id      inserted-till
                  :menu_item_id menu-item-id))))

xc4meron19:02:12

Im new to clojure and i'm really finding it difficult to code in it, i understand what the question is asking me i just need help coding it https://uva.onlinejudge.org/external/116/11615.pdf

andrew-clj19:02:13

Hello, I'm new to the group and new(ish) to clojure. I have been attempting to convert some Scala code, taken from Martin Odersky's functional programming course, into clojure. Here's a simple implementation of finding a close approximation of the square-root of a number. First the Scala version

def sqrtStream(x: Double): Stream[Double] = {
 		def improve(guess: Double) = (guess + x / guess) / 2
 		lazy val guesses: Stream[Double] = 1 #:: (guesses map improve)
 		guesses
 	}                                       
 	sqrtStream(4).take(10).toList             //> res0: List[Double] = List(1.0, 2.5, 2.05, 2.000609756097561, 2.0000000929222
                                                                                      //| 947, 2.000000000000002, 2.0, 2.0, 2.0, 2.0)
and my clojure attempt
(defn sqrt-stream
  "Takes a double and returns a lazy-sequence of doubles."
  [x]
  (defn improve [guess] (/ (+ guess (/ x guess)) 2))
  (let [guesses (cons 1 (lazy-seq (map improve guesses)))]
    guesses))
   
(take 10 (sqrt-stream 4))
There are 2 issues with this. Firstly I get an error message ' java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to java.lang.Number' for the line where the improve function is defined. Secondly, map already returns a lazy sequence so do I need create a new one? If someone could kindly point out my 'rookie' mistake I'd be most grateful. Many thanks

seancorfield19:02:15

Hmm, can’t help with that exercise @xc4meron — I have no idea what it’s even asking!

seancorfield19:02:47

@andrew-clj: Can you provide some details and explain where you’re having difficulty?

xc4meron19:02:21

Well the bit im stuck at is where i need to traverse the tree and find 2 nodes and count the amount of nodes in the subtree of the nodes im looking for

jeff.engebretsen19:02:20

@xc4meron: I also can't understand what they're asking. Can you explain how they're getting the results?

xc4meron20:02:39

You've got to traverse the tree and fined two nodes that you pass in, if both the nodes have subtrees you need to count how many they have in common. say there was 15 nodes all together in this BST if node 4 and node 5 are passed in then the output should be 13 as they both have subtrees thats are 2 so it cancels the other out

xc4meron20:02:51

It's so difficult to do

jeff.engebretsen20:02:19

I'm still not following. Can you explain how they got the answer for the example that they give where 4 and 12 has 15 different people?

jonahbenton20:02:30

hey @andrew-clj welcome. couple points- the defn form in clojure is different from def in scala. you probably want to use clojure's letfn to create a local closure.

andrew-clj21:02:56

Thank you @jonahbenton. I'd seen defn used inside another defn in a blog post example. I wasn't aware of letfn. There's a good discussion of the differences and usages between the 2 on Stackoverflow: Clojure style: defn- vs. letfn http://stackoverflow.com/questions/23255798/clojure-style-defn-vs-letfn That said, if I change the inner defn to the letfn form I now get java.lang.IllegalArgumentException: Don't know how to create ISeq from: clojure.lang.Symbol for that function definition. With regards to creating the lazy sequence, I confess that I don't really understand how using map in the Scala version works. We need to start with 1 then the second element is (improve 1) which gives 2.5. The third element is (improve 2.5) which gives 2.05...etc. Using map should return a new sequence with every element altered but we don't want each element altered, just a new one added. Recursion always makes my head hurt.

donaldball21:02:10

@andrew-clj: The most idiomatic expression would probably be: (defn sqrt-stream [x] (iterate (fn [guess] (/ (+ guess (/ x guess)) 2)) 1.0))

andrew-clj21:02:02

Super! Thank you @donaldball. I didn't know about iterate either. It's also a lot neater than the Scala version!

akiva21:02:04

@andrew-clj, you might want to take a look at http://clojuredocs.org/quickref or http://conj.io. Both offer a good overview of the available functions. http://conj.io is better for quickly finding something but http://clojuredocs.org is more up-to-date.

andrew-clj22:02:05

@akiva: thank you. I already have the clojure cheatsheet bookmarked and have now added the 2 you mentioned.