Fork me on GitHub
#beginners
<
2017-11-10
>
athomasoriginal00:11:31

I am going through some algorithm problems and I am curious, if one needed to, how would you execute a nested for loop (yes, this is ugly, but I am curious) - or maybe there is a way to get the same effect in the functional paradigm but not do it? You will start with a vector n items and at the end, end up with another vector of considerably less items...

noisesmith00:11:20

for is not a loop, it is a list comprehension, and it can do nested iteration and filtering

noisesmith00:11:44

you can also do nested loops if that's what you mean

athomasoriginal00:11:07

Sorry, for loop mean an imperative for loop - like in JS or Python

dpsutton00:11:18

(map (fn [thing] (map ...) ...) would also be a nested loop idea as well

noisesmith00:11:47

@tkjone the first question is whether the important thing is the data output, or some side effect done while consuming the input?

athomasoriginal00:11:11

The important thing is the output

noisesmith00:11:24

OK - for can do nested iteration with filtering easily

noisesmith00:11:35

Clojure 1.9.0-RC1
+user=> (pprint (for [x (map range (range 10)) y x :when (zero? (mod y 3))] [x y]))
([(0) 0]
 [(0 1) 0]
 [(0 1 2) 0]
 [(0 1 2 3) 0]
 [(0 1 2 3) 3]
 [(0 1 2 3 4) 0]
 [(0 1 2 3 4) 3]
 [(0 1 2 3 4 5) 0]
 [(0 1 2 3 4 5) 3]
 [(0 1 2 3 4 5 6) 0]
 [(0 1 2 3 4 5 6) 3]
 [(0 1 2 3 4 5 6) 6]
 [(0 1 2 3 4 5 6 7) 0]
 [(0 1 2 3 4 5 6 7) 3]
 [(0 1 2 3 4 5 6 7) 6]
 [(0 1 2 3 4 5 6 7 8) 0]
 [(0 1 2 3 4 5 6 7 8) 3]
 [(0 1 2 3 4 5 6 7 8) 6])
nil

noisesmith00:11:36

for reference

+user=> (pprint (map range (range 10)))
(()
 (0)
 (0 1)
 (0 1 2)
 (0 1 2 3)
 (0 1 2 3 4)
 (0 1 2 3 4 5)
 (0 1 2 3 4 5 6)
 (0 1 2 3 4 5 6 7)
 (0 1 2 3 4 5 6 7 8))
nil

athomasoriginal00:11:55

Neat. My hang up was that for some reason I thought I would have to stick with maps and reduces and using for would not be savvy

athomasoriginal00:11:36

The thing I am doing is taking a vector [1 2 3] and I need to compare each item against every other item in the vector

noisesmith00:11:14

(for [x [1 2 3] y [1 2 3] :when (some-fn x y)] ...) - for example

noisesmith00:11:33

there's also a :let key

noisesmith00:11:50

+user=> (let [v [1 2 3]] (for [x v y v :let [same? (= x y)]] same?))
(true false false false true false false false true)

athomasoriginal00:11:44

Thanks, I will play with those - def' given me better understanding of how they can be used

dpsutton00:11:12

you can also use maps like that as well:

(let [coll [1 2 3]]
  (map (fn [v] (map #(compare v %) coll)) coll))
((0 -1 -1) (1 0 -1) (1 1 0))

Orco19:11:01

Do you by any chance get the followin error when running the code @noisesmith posted? ClassCastException clojure.lang.PersistentList$EmptyList cannot be cast to clojure.lang.IFn user/eval1274 (form-init5831160276747267566.clj:1)

noisesmith19:11:05

I pasted that directly from a clojure.jar repl

Orco19:11:05

ok. I'm using clojure "1.8.0", so I was wondering whether that could be the reason...

Orco19:11:52

Nevermind, I figure out what I was doing wrong 😛

Eddie00:11:10

@noisesmith Thanks so much for the info on types!

Eddie02:11:16

@noisesmith I got a deftype working that implements IPersistentCollection and Associative. Very cool stuff. I am having a more difficult time figuring out how one would control what is considered the "items" when map-ing a function down a user defined type. For example, if we have a deftype with an bunch of fields, one of which is called something like :data or :table and we would like (map f thing-of-our-type) to be the same as if we did (assoc thing-of-our-type :data (map f (:data thing-of-our-type))) what interface would we have to implement to achieve this? java.lang.Iterable maybe?

sundarj03:11:42

map has existing and well-defined behaviour. i would imagine that different behaviour would (and should) require a different function, like with a protocol. i do not much about this kind of thing though.

Eddie03:11:45

@sundarj I suppose that makes sense. Thanks!

tbaldridge05:11:20

@erp12 Clojure.lang.Seqable is the interface you want.

lepistane09:11:29

Hi guys is there a way to specify which lein version should be use for specific project only? For some reason tests fail when using 2.8 we suspect it's a bug but we need to investigate more. So we wanted to use 2.7 specifically only for that project is there a way to do that?

jumar10:11:53

I guess it depends how you run your tests. You can install multiple leiningen versions and use the 2.7 version for the specific project If you use brew on MacOS you can access the old versions e.g.

/usr/local/Cellar/leiningen/2.7.1/bin/lein
I'd say it's mostly packaging system question

wilcov13:11:43

i've got a really general question which probably won't have a definitive answer: We (2 man team starting own web development company) have gotten a request to implement to supply a system that handles paid subscriptions for a fitnes site (customer information, payment and content reminders, intergration with 3ed party payment provider). Being impressed with clojure my hope is that clojure (i.e. with yada/bidi and datomic) would be a good fit for it. in short: would it be wise? or am i deluding myself because i happen to like the language. (I'm experienced in php and python, but still a beginner in clojure)

adityaathalye13:11:06

IMHO, pick familiar tools, and focus on the customer's needs / problems. Alternatively, get the customer's sign off on the idea of using a core tool that's new to you. Best wishes for a successful project :spock-hand:

orestis14:11:20

I struggled with this some time ago; not with Clojure, but with Elixir. After much consideration, I decided to build only a small (and easily replaceable) part of the system in Elixir. I picked a component that was self-contained, had very few dependencies, and didn’t have to save data.

orestis14:11:09

Especially for persistence, I say go with what you know.

orestis14:11:01

In your particular case, perhaps I would try to build the reminder system in Clojure.

wilcov14:11:23

I think you're both right that it would be smarter to use languages that i'm more comfortable in. @U7PBP4UVA how did your self-contained elixer part work out? Are you happy with it?

orestis14:11:40

Extremely happy! Keep in mind, it played into the strengths of Elixir (communicating in parallel with ~200 machines on a private network), and out of the weaknesses of Python.

orestis14:11:47

I still had a few “oh-shit” moments that I had to resolve even for a relatively simple component. Which is why I say “pick something simple”, no matter the language, you will have “unknown unknowns”, best to keep those confined to a single part of the system than let them permeate your entire stack.

wilcov14:11:02

I'm glad the part worked out for you, and regarding the unkown unkowns, that sounds like good advice. I'll try and find a small, non-critical part of the system where i can use clojure

wilcov14:11:04

and with communication between 200 machines it sounds like it was a cool project to work on

wilcov14:11:09

Thanks to both of you for the advice

jaymartin14:11:52

The Self-Contained Systems pattern might be of interest as you strive to mix languages: http://scs-architecture.org/

jaymartin14:11:47

But it might also add undue complexity as many people like to start out with a monolith and then break things up.

adityaathalye15:11:17

Most welcome, @U3675LFHP Here are a couple of more thoughts 1. Use Clojure to write things like functional test suites (UI automation etc.) --- lower the risk of tool-originating failure, for you and for the customer, and also create a QA resource for yourself that you could carry from project to project. 2. Once you've understood the customer's problem and solved it satisfactorily, perhaps see if you can rewrite a small part of it in Clojure. (And again, best wishes! As a fellow freelance/independent engineer, I know how it is to take on new/greenfield projects.)

manutter5113:11:28

Personally I would not commit to delivering a production system built in a language I was new to, not if money was involved. You’ll want at least one experienced Clojure dev on board, or one good production-ready not-for-money system built, IMO.

wilcov14:11:11

@manutter51 thanks for your reply, i think you're right. unfortunately i don't think we can spare the funds to hire a experienced clojure dev at the moment, so we'll probably confine clojure to a small, non-critical part of the system as orestis suggested.

Leo E16:11:33

So if I want to use clojure-script in my leiningen project should I use this http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22clojurescript%22%20g%3A%22org.clojure%22%20 or should I use the jar from their website?

Eddie16:11:42

Does anyone have any tips on figuring out what interfaces need to be implemented to get certain functionalities in our deftypes? So far you all have been very helpful, but I would hate to continuously spam here until I commit this stuff to memory 🙂 For example, I have a deftype that implements clojure.lang.Associative but it fails on get. Are there any docs that can be used to figure out which interface will allow support for get?

Eddie16:11:03

@noisesmith suggested starting from here (supers (class {})) or something similar which is a really good start, but I am having having trouble figuring out which super(s) provide support for a given Clojure built-in function.

adityaathalye16:11:56

I was going to suggest something similar:

user=> (defrecord Foo [])
user.Foo
user=> (-> (->Foo) class supers clojure.pprint/pprint)
#{clojure.lang.Seqable clojure.lang.Counted java.lang.Iterable
  clojure.lang.IObj clojure.lang.IMeta clojure.lang.IPersistentMap
  java.io.Serializable clojure.lang.IRecord java.util.Map
  clojure.lang.IPersistentCollection clojure.lang.IKeywordLookup
  java.lang.Object clojure.lang.IHashEq clojure.lang.ILookup
  clojure.lang.Associative}
nil
Which is to say, a type that implements all these interfaces will be indistinguishable from a record (at least at this level)

noisesmith17:11:54

There's two details here: you can look in the javadoc or Java source of each of those interfaces to see the methods it implements, and you can look at the source of clojure functions to see which methods (or deeper functions etc) they need

noisesmith17:11:04

The functions clojure.repl/javadoc and clojure.repl/source can help

tdantas17:11:56

I’m getting a weird issue

(defn my-fn [f] (var f))

CompilerException java.lang.RuntimeException: Unable to resolve var: f in this context, compiling:(/private/var/folders/bd/np6270sn31j1d0z3zhl82tjh0000gn/T/form-init7905493545882869081.clj:1:13) 
why (var f) is being evaluated before I call the function

sundarj17:11:34

it's a special form, evaluated at read time

sundarj17:11:35

never mind, this is wrong

reborg17:11:05

@oliv f must be a var (i.e. defined with def). You are attempting to capture a local binding "f" which is just a symbol. What's the goal anyway?

tdantas17:11:17

I’m just playing around to understand the difference of #’full-name against passing only the symbol in the example below

(defn full-name [] "Oliv")
(defn greetings [honorific f] 
	(fn [] 
		(str honorific " " (f))))

(def mr-name (greetings "Mr." full-name))
(def sr-name (greetings "Sr." #'full-name))

(mr-name)
(sr-name)

(defn full-name [] "Olivia")

(mr-name)
(sr-name)

tdantas17:11:01

sr-name , is using the var instead of the symbol full-name . once I change the full-name function, sr-name changed as well

reborg17:11:19

full-name is a var, so essentially a name-value pair. Your defs of mr-name and sr-name are sending to the function greetings the var full-name, not the value of the var at that point. The var is local-bound to "f" (just an alias) and de-reffed at the point where (f) is invoked.

reborg17:11:36

Some confusion is generated when you type full-name at the REPL, which calls (eval full-name) and eventually ends up in de-reffing the var for you. That's why you have (var full-name) to actually access the var. But when is not at the REPL, full-name or #'full-name are resolving to the same thing.

tdantas19:11:20

hey @reborg I just ran: example.clj

(defn full-name [] "Oliv")
(defn greetings [honorific f] 
	(fn [] 
		(str honorific " " (f))))

(def mr-name (greetings "Mr." full-name))
(def sr-name (greetings "Sr." #'full-name))

(println (mr-name))
(println (sr-name))

(defn full-name [] "Olivia")

(println (mr-name))
(println (sr-name))
lein exec example.clj

tdantas19:11:33

the output was:

Mr. Oliv
Sr. Oliv
Mr. Oliv
Sr. Olivia

tdantas19:11:55

the sr-name was changed

athomasoriginal21:11:01

Dove into the for loop yesterday which is awesome for the problem I was solving. I want to optimize it a little more though, for example, if I have a vector like [ [1 3 ] [ 1 5] [2 4 ] ] and I do something like

(for [x sorted-v 
        y sorted-v]
  (some-logic))
The first "iteration" (not sure what its called actually) would allow me to compare 1 3 and 1 3 second iteration would be 1 3 and 1 5 etc. Cool, but when I get to the end, and everything increments, the iteration would be 1 5 and 1 3 . thing is, I have already compared these two, in a different order, but the comparison for my purposes is done. Is there a way to force an increment, or keep local mutable state with these loops? My thought was create a set of already compared comhinations

seancorfield21:11:07

@tkjone I think a loop would be better for that situation but it's hard to tell without more detail about what you're trying to do.

seancorfield21:11:36

for produces a lazy sequence for consumption -- it's not like a for loop in other languages. It isn't really a "loop" at all.

athomasoriginal21:11:05

I would like to compare each item against every item in the vector

seancorfield21:11:48

And do what with the result of that comparison? That's the key part.

athomasoriginal21:11:23

Return a collection of vector pairs that match a condition

seancorfield21:11:20

I still think loop with an accumulator will be better.

athomasoriginal21:11:17

Okay, I will checkout the loop

phronmophobic21:11:40

what about something like

(for [x sorted-v 
      y sorted-v
      :when (matches-condition? x y)]
  [x y])

athomasoriginal22:11:34

Thats actually similar to what I have now, which works, but I wanted to avoid further comparing vector items that have already been compared

phronmophobic22:11:36

(for [[i x] (map-indexed vector sorted-v) 
      y (subvec sorted-v i)
      :when (matches-condition? x y)]
  [x y])

phronmophobic22:11:22

not sure if that’s better than just using loop

seancorfield22:11:04

OK, here's a solution using for that might satisfy you @tkjone

(for [[x :as xs] (take (count sorted-v) (iterate next sorted-v))
      y xs
      :when (matches-condition? (x y)]
  [x y])

athomasoriginal23:11:06

This is actually a really interesting approach. Question about iterate - it does not apply the function on the first iteration, correct?

seancorfield23:11:42

Correct

(take 10 (iterate inc 0))
=> (0 1 2 3 4 5 6 7 8 9)

seancorfield22:11:51

(I expect there's a cleaner way of getting that iterated sequence)

athomasoriginal22:11:14

Thank you. I will take a look at both solutions, but to be clear, you would say a loop might be the better choice?

sundarj22:11:56

@tkjone here's something with reduce (similar to loop):

(->> [[1 3] [1 5] [2 4] [10 8]]
     (reduce
      (fn [[seen result :as acc] [x y :as val]]
        (if (some #{val} seen)
          acc
          [(conj seen val) (conj result (< x y))]))
      [[] []])
     ((fn [[_ result]] result)))
[true true true false]

seancorfield22:11:07

Well, you are not really iterating over the elements of the sequence, you are performing filtering on the sequence, the rest of the sequence, the rest of the rest of the sequence etc.