Fork me on GitHub
#beginners
<
2018-10-24
>
noisesmith00:10:05

(let [winner (promise)] (future (search-google-fn) (deliver winnner :google)) (future (search-bing-fn) (deliver winner :bing)) @winner)

CyberSapiens9700:10:06

yes, i'm saying parallelism because as i'm studying, it's said that concurrency is more about running in alternating mode, and parallelism is about running together. and i'm seeing futures delays and promises as concurrency mechanisms

CyberSapiens9700:10:31

thanks @noisesmith that makes sense, because promises can only be delivered once right...

noisesmith00:10:52

right, and it's a no-op to deliver to one that is already delivered, so it's safe

CyberSapiens9700:10:55

so, for a lot of concurrent problems we can just combine futures delays and promises :thinking_face:

noisesmith00:10:21

yeah - my example could deadlock if both futures failed btw

noisesmith00:10:42

so for real code you might need a timed-out deref or some other failsafe

noisesmith00:10:29

deref takes an optional timeout arg if you use the function form and not the reader macro

noisesmith00:10:38

it's pretty straightforward to use

noisesmith00:10:57

`(deref winner 10000 :fail)`

noisesmith00:10:14

declare simple failure if both take more than 10 secs, in that example

hiredman00:10:48

but core.async comes with various forms of alt!, which chooses between channels

CyberSapiens9700:10:55

awesome, concurrent programming seems very easy and fun to code with CLJ

noisesmith00:10:57

one problem, the timeout option to deref doesn't work with promises

awb9900:10:14

I just installed leiningen on majaro/arch, and it does not like me using it as non sudo user. I don't have anything special in my system. Any ideas??

hiredman00:10:01

"This could be due to a typo in :dependencies, file system permissions, or network issues."

hiredman00:10:26

looks like a typo in dependencies,

noisesmith00:10:28

I bet when you used sudo you made broken perms on .m2

hiredman00:10:43

Failed to resolve version for re-frame:lein-template:jar:RELEASE:

awb9900:10:49

@hiredman I just did "lein new re-frame arduino"

hiredman00:10:53

RELEASE isn't a real version

hiredman00:10:12

whoever made the template maybe didn't do a good job

awb9900:10:36

I have the same issue with lein without using sudo for my other test project.

awb9900:10:54

I think possibly lein on arch is being setup incorrectly.

noisesmith00:10:12

the re-frame template is fine, I was able to use it

noisesmith00:10:16

what lein version?

awb9900:10:12

lein --version Leiningen 2.8.1 on Java 1.8.0_181 OpenJDK 64-Bit Server VM

awb9900:10:02

yaourt -S leiningen

awb9900:10:09

I think leiningen on arch/manjaro is broken.

awb9900:10:20

With sudo, everything works.

awb9900:10:25

But without sudo nothing works.

hiredman00:10:59

what are your permissions on ~/.m2?

hiredman00:10:11

my guess is ~/.m2 isn't owned by or isn't read/writable by your user

awb9900:10:34

ls ~/.m2 -alfg total 12 drwxr-xr-x 74 andy 4096 Oct 23 19:12 repository drwx------ 84 andy 4096 Oct 23 19:04 .. drwxr-xr-x 3 andy 4096 Oct 16 08:22 .

awb9900:10:36

chmod -R a+rwx ~/.m2

awb9900:10:40

this did not do the trick.

awb9900:10:46

@hiredman So all local repositories are kept in @.m2 ?

awb9900:10:56

This is very different to how node does it.

awb9900:10:00

Good to know!

hiredman00:10:23

.m2 is a cache

hiredman00:10:00

it is originally used by maven, but maven derived tools also use it now too

peter-kehl00:10:55

A follow up on 'idiomatic' (seq x) rather than (not (empty? x)). The idiomatic seq pulls a whole sequence - not friendly to lazy. An example (with the side effects being intentional to show the difference):

(not (empty? (for [i '(1 2)] (do (println "i:" i) i))))
i: 1
true
but
(seq (for [i '(1 2)] (do (println "i:" i) i)))
i: 1
(i: 2
1 2)
Plus, idiomatic (seq [1 2 3]) turns it into a sequence. If all you want is to act if it's not empty, isn't that processing into a sequence a waste?

CyberSapiens9700:10:17

when i want to act if it's not empty, i simply do (if coll ... ...)

👍 4
CyberSapiens9700:10:30

because seq treats empty collections as nil

CyberSapiens9700:10:44

and nil is falsey

andy.fingerhut00:10:15

@peter.kehl seq is pulling the whole sequence in your example only because it is the top level form at the REPL, so you are asking it to print the entire result, if it can.

andy.fingerhut00:10:50

It won't do that if you use it in a context where you are not forcing it to evaluate the entire result.

andy.fingerhut01:10:44

(if (seq (for [i '(1 2)] (do (println "i:" i) i))) :not-empty :empty)

TK01:10:34

How do I design/organise functional code in a simple system? Do I put some data structures in separated namespace? Would the core.clj include all namespaces to use their functions? Any resource/advice? 🙂

andy.fingerhut01:10:03

@leandrotk100 First quick suggestion, but then I'm close to out of advice given my mostly hobby use of Clojure -- There is no need to have a file named core.clj in a project, even though the Leiningen templates often create one. In fact, you may want not to have such a file name, because stack traces often include only the last component of the file name in addition to function names (not the whole file path name), and clojure.core functions show up as in file core.clj

andy.fingerhut01:10:37

It is useful to try to make as much of your code as you can in pure functions of their arguments, taking immutable data and returning immutable data, and try to keep IO and any mutable data "at the edges", if you can.

awb9901:10:16

@leandrotk100 In IntelliJ / Cursive instead of adding .clj files, you have a menue to add a namespace. IntelliJ will then automatically create the file in the right folder. I like this feature. It makes it more logic to Clojure, namely you only think of namespaces, and not of source-code files. This does not answer your question, I just thought you might want to have a look at this feature.

TK02:10:57

@andy.fingerhut And how do I know how to separate functions in a different file/namespace?

andy.fingerhut02:10:03

@leandrotk100 The book "Clojure Applied" has a section with recommendations on this topic, but unfortunately I haven't read it yet. Passing on the info in case it might be of interest. I would bet others with more experience may add their suggestions here later.

TK02:10:20

What do you mean "at the edge" in try to keep IO and any mutable data "at the edges"?

TK02:10:37

I'll take a look at this book!!

andy.fingerhut02:10:33

A rough example - You want to read in some chunk of data from a database or file, transform it in some way, then push it to another database or file, where the assumption for this example that the 'transform' step can be written as a pure function taking immutable data as args, and returning immutable data. Rather than combining all of that into one function, separate out the 'transform' part into a pure function, and the reading and writing parts into their own functions, then have a combined small function that calls all 3. The 'transform' function is then potentially easier to do example-based or generative tests on.

mbjarland07:10:28

I’m writing a small function which takes a java process object and a “line handler” function, traces the stdout of the process and calls the line handler for each line of output. Specific problem, but I have a generic question. I would like to use lineseq for the above if possible as it seems like the highest level abstraction. What closure construct would be most suitable for iterating through a seq and optionally exiting the iteration on certain conditions. I.e. doseq et al are out it seems. Am I reduced to using reduce ; ) or is there a more suitable tool?

mbjarland07:10:57

ah, perhaps take-while - RTFM as usual…I retract my question

ClojureNoob09:10:12

Hi all!

👋 28
4
rakhim14:10:48

Hi all! I'm trying to split a string into sentences while preserving all punctuation. Using regular split removes the matched delimeters. I thought I could achieve this with a regex group like this, but no 🙂

> (clojure.string/split "goo. boo? foo! no!!" #"(<=[.!?]|[.!?][\\'\"])\s+")
["goo. boo? foo! no!!"]
Can't figure out what am I missing...

rakhim14:10:43

oh snap! it's a typo!

rakhim14:10:49

(clojure.string/split "goo. boo? foo! no!!" #"(?=[.!?]|[.!?][\\'\"])")
["goo" ". boo" "? foo" "! no" "!" "!"]

rakhim14:10:55

this works.

rakhim14:10:00

thank you all! 😄

rakhim14:10:46

yeah, almost there...

manutter5115:10:36

@rakhim I’d recommend using re-seq instead of clojure.string/split, you’ll have more control over what you get back.

manutter5115:10:07

I can give you an example unless you’d rather have a hack at it yourself.

rakhim15:10:49

woah, this is what I needed!

rakhim15:10:57

I got this so far

> (clojure.core/re-seq  #"[a-z,;'\"\\s]+[.?!]" "goo. boo? foo! no!!")
("goo." "boo?" "foo!" "no!")

rakhim15:10:13

Here is a better version, if anyone is interested

> (clojure.core/re-seq  #"[^\.\!\?]*[\.\!\?]+" "Free goo etc. and else. Boo? Foo! no!!")
("Free goo etc." " and else." " Boo?" " Foo!" " no!!")
This actually matches sentences, not just one-word sentences like the prev. version. Now, the next challenge is to ignore common words that end with a period, but don't necessarily signal the end of a sentence (`e.g.`, etc., Dr. and such)

andy.fingerhut16:10:37

I actually tried writing some code to separate sentences in books many years ago, and yeah, it isn't as simple as it sounds at first 🙂

andy.fingerhut16:10:17

So many things humans with 10 years of education can do that are hard to write down.

rakhim16:10:54

I'm still struggling, yeah. There are also .com and a myriad of other cases...

Braden Shepherdson16:10:08

human language is insanely hard from a computing point of view. TeX's logic for splitting text into multiple lines with hyphenation is as complex as the AI for a modest game, weighing the "badness" of possible ways to break the lines.

dpsutton16:10:21

i think emacs solves this by insisting on two spaces after periods to disambiguate it from a period after an abbreviation

andy.fingerhut16:10:31

There may be some open source NLP (Natural Language Processing) libraries that already cover a lot of these things, but I've not used any of them to give any recommendations. If you are hacking for fun, go for it! If you have a paid job to do with lots of requirements, might want to look into existing code to see if it does what you want.

☝️ 4
dpsutton16:10:44

running checkdoc on elisp code will throw warnings with docstrings without proper punctuation or only a single space after a period

andy.fingerhut16:10:26

Huh, I just came across a person from France recently who wondered why so much text they were reviewing, written by others, used double spaces. There are whole factions and articles written saying that two spaces is a hold-over from manual/electric typewriters with monospace 'fonts', and single spaces should always always always be used in this modern age.

andy.fingerhut16:10:05

Emacs being on the double-space side of that argument makes sense 🙂

andy.fingerhut16:10:34

Even "studies" written: A Google search for the following terms finds a bunch of them, in case you wish to indulge time on the matter: single vs. double spaces at end of a sentence

rakhim16:10:09

It's a hobby project, but regexes are no fun 🙂 I'll look into NLP libraries, thanks for a suggestion.

rakhim16:10:35

This looks promising https://github.com/dakrone/clojure-opennlp

(pprint (get-sentences "First sentence. Second sentence? Here is another one. And so on and so forth - you get the idea..."))
["First sentence. ", "Second sentence? ", "Here is another one. ",
 "And so on and so forth - you get the idea..."]

rakhim16:10:36

This is pretty cool, but, from the first glance, seems like it's for a different case.

hoynk18:10:26

Is there a nice "utils" library that has all the little things clojure doesn´t, like leftpadding a string, that works in both clojure and clojurescript?

andy.fingerhut18:10:32

there are several!

hiredman18:10:57

user=> (format "%1$5s" "Yo")
"   Yo"
user=> 

andy.fingerhut18:10:58

well, by which I mean there are several public utils libraries. Most likely none of them include everything you might wish for.

andy.fingerhut18:10:15

@hiredman format in Clojure/Java is based on JVM format, which has different format strings than the ClojureScript implementation, doesn't it?

hiredman18:10:12

very likely

zlrth18:10:46

I have a function

(defn do-a-thing
  [account-number & [{:keys [unpublish?]}]]
  (do-stuff account-number unpublish?))
that I want to call from both lein run -m, and inside my program. It accepts args like: (do-a-thing 100 {:unpublish? true}). Can I call that from the command line? Maybe stringify it? But then, how do I parse the options? I could do:
(defn do-a-thing
  [s]
  (apply do-a-thing (parse-opts s))
  [account-number & [{:keys [unpublish?]}]]
  (do-stuff account-number unpublish?))
but i've never seen anyone else do that. seems nonobvious that the one arity is for calling from the command line.

chrisulloa18:10:19

Have you considered looking into CLI libraries for Clojure?

chrisulloa18:10:08

The heavy lifting for parsing command line arguments can be done with libraries like clojure/tools.cli. I presume there is a way to take args and build a map.

zlrth18:10:57

yeah i got parse-opts there; i was referring to tools.cli in that case. i'm thinking about it!

andy.fingerhut18:10:29

Yeah, actually the public utils libraries I am most familiar with might be specific to Clojure on Java -- I suspect there are some that stress working similarly/same on both Clojure and ClojureScript, but I am not as familiar with which ones those are.

timmyjose18:10:05

Hello, all! I am a beginner in Clojure, and I have got a bit of a problem with my code. I am trying to write a simple function that will simply generate pairs of adjacent numbers of a collection to check if the collection is sorted. I tried without using eval, but the code doesn't work (presumably due to laziness). I would rather not use eval. What would be the best way to approach this without changing the main logic itself? Here is the code for the same:

(ns sorted)

(defn pairs [xs ys]
  (partition 2 (interleave xs ys)))

(defn sorted [xs]
  (eval (apply #'and (doall (for [pair (pairs xs (rest xs))] (< (first pair) (second pair)))))))

(defn -main []
  (let [coll [1, 2, 3, 4, 5]]
    (sorted coll)))

jaihindhreddy05:10:16

It's convention to end predicate names with ?. Also, < is polymorphic so you can implement it like so (defn sorted? [xs] (apply < xs)) Make sure you want < and not <=. Depends on whether you want to check for an increasing sequence or a non-decreasing sequence.

jaihindhreddy05:10:23

If you want to do the pairwise comparison, you can do it more concisely using partition like so: (defn sorted? [xs] (->> xs (partition 2 1) (every? #(apply < %))))

timmyjose18:10:34

Ignore the doall in there, by the way... the behaviour is the same without that...

hiredman18:10:38

absolutely not

andy.fingerhut18:10:24

@mfm The command line is strings only, not Clojure data, so I don't see a way to provide a CLI interface that tries to leave out the parse step. The parse step can be as simple as calling an existing function like clojure.edn/read-string, if you want that syntax for the strings in your CLI

hiredman18:10:28

you want something like (every? #(<= (first %) (second %)) (partition 2 1 numbers))

timmyjose18:10:09

Let me try that out and see... looks like that's exactly what I want

hiredman18:10:59

there is so much wrong with that it is hard to know where to start with it

chrisulloa18:10:31

@timmyjose Maybe a better way would be to check if the sequence is monotonic. Only checking two at a time in the collection xn-1 < xn and short circuiting if any pairs fail.

hiredman18:10:18

you have two mechanisms for generating pairs

andy.fingerhut18:10:19

(apply <= coll) might do it

👍 4
hoynk18:10:27

I know some of my code will be re-used in the clojurescript front-end... so I was trying to minimize having to rewrite some stuff later.

hiredman18:10:37

for + rest and partition

timmyjose18:10:48

@hiredman Yes, that works indeed. Just curious how the original approach could be made to work without eval (using list comprehensions) without getting bogged down by the lazy seq?

hiredman18:10:56

you are applying the macro and as a function

hiredman18:10:03

and you are calling eval

ange18:10:11

Hello all, beginner to clojurescript, trying out hoplon, How does one get the mouse position on mouse events?

zlrth18:10:14

@andy.fingerhut thanks! i was thinking of parse-opts in tools.cli because that'd handle multiple arguments from the command line, but edn/read-string would be simple, and less of a dependency. thanks!

timmyjose18:10:46

@christian.gonzalez Yup.. that's what I thought would work by using and... no luck though

andy.fingerhut18:10:01

@mfm it does require your users to appropriate quote the strings, if they have internal spaces, braces, etc. stuff that the shell has its own ideas about.

chrisulloa18:10:14

<= is used for checking if collections are monotonic so andy.fingerhuts suggestion is probably best

timmyjose18:10:02

Ah, right... sorry, that is a typo in my code... I did mean <= ...

chrisulloa18:10:12

<= does a loop recur on multiple args that does what I suggested

timmyjose18:10:29

but I was trying to apply the and macro, and forcing it with eval... so avoid this approach entirely?

andy.fingerhut18:10:47

apply does not work with macros, only functions

andy.fingerhut18:10:16

Same for any other function like map, filter etc. that takes a function as its arg.

hiredman18:10:17

if you wanted to use eval, you cannot just apply and like that, you need to build a form to call eval on

hiredman18:10:24

but don't do that

timmyjose18:10:52

Okay, so getting some garbage value like (clojure.core/let [and__5236__auto__ true] (if and__5236__auto__ (clojure.core/and true) and__5236__auto__)) when using (apply #'and (for [pair (pairs xs (rest xs))] (< (first pair) (second pair)))) is totally expected, right?

timmyjose18:10:59

I mean... there was no error

noisesmith18:10:08

macros take forms and return forms

hiredman18:10:13

which would be something like

(eval `(and [email protected]))

noisesmith18:10:25

also, they have two invisible args (you can provide nil for each) before the real args

timmyjose18:10:18

Thanks, all. I am beginning to grok it all now... 🙂

noisesmith19:10:01

user=> (apply #'and nil nil '(:a :b :c :d))
(clojure.core/let [and__5236__auto__ :a] (if and__5236__auto__ (clojure.core/and :b :c :d) and__5236__auto__))
user=> (pprint *1)
(clojure.core/let
 [and__5236__auto__ :a]
 (if and__5236__auto__ (clojure.core/and :b :c :d) and__5236__auto__))
nil

timmyjose19:10:41

Yes, this is similar to what I was getting

noisesmith19:10:51

except it threw two of your args away

timmyjose19:10:05

Thanks again for the help, folks! Nice to see such an active community over here as well! Will be back again soon 🙂

👍 12