Clojurians
#clojure
<
2015-11-17
>

This page is not created by, affiliated with, or supported by Slack Technologies, Inc.

rpowelll00:11:12

Hey all, I’m very new to Clojure and I’ve been learning it by following through Clojure for the Brave and True, but right now I’m having an issue with one of the end of chapter exercises

rpowelll00:11:16

The task they put forth is to implement a function mapset which works like map, but returns a set instead of a vector

rpowelll00:11:22

my current solution looks like this:

rpowelll00:11:20

oh wait, I was calling it wrong, that solution totally works

rpowelll00:11:30

rubber duck’d my way out of this one I guess

dvcrn01:11:33

I saw people with clojure stickers on their laptop

dvcrn01:11:38

where can I get one? :simple_smile:

progzilla01:11:03

Me too I have been looking for it

mtnygard01:11:07

@dvcrn Are you at Clojure/conj by any chance? Stop by the Cognitect table for free stickers and extra parens.

dvcrn01:11:42

Sadly not. Anyone able to ship me one to Tokyo? :stuck_out_tongue:

mtnygard01:11:06

Message me your address. :-)

dvcrn01:11:31

:simple_smile:

progzilla01:11:38

Hope this not offensive? I wouldn't mind one too, am in the UK, London precisely?

lfn301:11:33

There’s http://clojure.org/swag if you’re not opposed to throwing down some cash. Take the spares to a clojure/fn-al programming meetup, you’ll make some friends.

dvcrn01:11:56

oh I didn't know about that

mtnygard01:11:49

@progzilla Hit me up.

progzilla01:11:24

@mtnygard where at?

mtnygard02:11:35

Send me a private message with your mailing address.

ghadi02:11:43

Colin Fleming made a nice talk about PEG grammars today at the conj... coincidentally I have been talking to him about a Parsing Library I have been working on based on PEGs. It is almost ready to release.

ghadi02:11:16

That is a grammar to parse JSON, in 100 LOC

ghadi02:11:30

it doesn't use parser combinators

ghadi02:11:01

instead there is a virtual machine underneath

ghadi02:11:35

I really like Lua's LPEG library, which this is somewhat derived from. I just wanted to bring the VM approach to Clojure. An extensive README is forthcoming.

ghadi02:11:55

it's alpha as heck.

danielcompton02:11:14

@ghadi: does this generate JVM bytecode?

progzilla02:11:32

@mtnygard thanks.

ghadi02:11:36

no it's custom bytecode oriented towards parsing

ghadi02:11:48

user level bytecode

danielcompton02:11:11

hehe, bytecode VM on JVM, on AWS VM, on real hardware

ghadi02:11:15

basically a grammar begins life as PODS (plain ol' data structures) -> then a compiler turns it into an AST -> then to "parsing bytecode" -> then it's run inside a virtual machine, built for parsing

ghadi02:11:54

the VM was...fun. We all know mutable state sucks. implementing mutable state itself is like the worst hell.

ghadi02:11:56

I'll write up a better rationale (hi @donaldball) but I think there is a very nice space between regexes and Instaparse.

ghadi02:11:23

PEGs are deterministic. Instaparse handles ambiguity

ghadi02:11:33

regexes should die in a fire

clumsyjedi02:11:20

Can anyone explain this behaviour?

user=> (def f ( "/Users/clumsyjedi/file"))
#'user/f
user=> (def s ( f))
#'user/s
user=> (.delete f)
true
user=> (slurp s)
"lol\n”

clumsyjedi02:11:02

the file being slurpable after the file is deleted? I suspect this only works on files up to a certain length

clumsyjedi02:11:09

and is not something one can rely on

lfn302:11:20

@clumsyjedi: This is conjecture, but I assume that the stream in this case is at least a little bit eager. That eagerness is probably an implementation detail. Slurping f in the above example fails, correct?

clumsyjedi02:11:48

yes, FileNotFoundException

lfn302:11:56

Yeah so I think clojure generally uses Java’s buffered streams - probably on construction of that it’s ripping in the first n many bytes to it’s buffer.

clumsyjedi02:11:19

ok cool, thanks

clumsyjedi02:11:45

it would be great to figure out what that n is, but I’m too lazy to go look at the BufferedStream code

clumsyjedi02:11:52

:simple_smile:

mj_langford04:11:34

going off unix foo, not knowledge about the java classes: deleting a file unlinks it from the file system, but doesn’t close open file descriptors. I assume this is what you’re seeing here

mj_langford04:11:00

many file systems basically work of something garbagecollection esque

mj_langford04:11:24

delete is merely removing a single reference to the datum on the filesystem

clumsyjedi06:11:45

interesting point mj_langford , and calling the attached script as

[email protected] ~ $ echo lol > foo; perl ~/test_delete.pl
backs you up

mbertheau09:11:20

Hmm, so I can't use ({:a 1} a-map) as a shortcut for (get a-map {:a 1})? Why not?

mishok1309:11:59

because clojure.lang.HashMap doesn't implement IFn, unlike keywords

mishok1309:11:31

or simply put: hash maps can't be used as functions

mbertheau09:11:24

So the shortcut is only for keywords really?

mbertheau10:11:30

Hmm, vectors are recommended over lists, but functions like concat return a list and there's no concatv.

mbertheau10:11:32

Is there a shorter way to express (vec (concat (when a [a]) (when b [b])))?

malch10:11:19

@mishok13: Sorry, but you are wrong

malch10:11:29

user=> ({:a 3} :a)
3

agile_geek10:11:45

Actually APersistentMap extends AFn so you can use a map to lookup a key regardless of whether the key is a keyword BUT you need to put the map with the key first i.e.

(a-map {:a 1})
assuming a-map has {:a 1} as a key

agile_geek10:11:23

keywords are also fn that look themselves up in maps.

agile_geek10:11:52

so you can use

(:a {:a 1})

agile_geek10:11:28

or

({:a 1} :a)

agile_geek10:11:54

but only

({“a” 1} “a”)
for a String key

agile_geek10:11:35

as String is not a fn so

(“a” {“a” 1})
doesn’t work

malch10:11:04

@mbertheau:

user=> (filter identity [nil :b :c])
(:b :c)

malch10:11:14

if I understood correctly

moxaj10:11:41

Question: say I have a data structure [1 2 3 (identity 4)], is there any way I can make a macro receive [1 2 3 4] as its argument (not a symbol with [1 2 3 4] as its value, because I need access to parts of it at compile time) ?

robert-stuttaford11:11:04

100% of what macros receive is data, @moxaj. the whole idea is that you can manipulate the code as data before its’ compiled as code

moxaj11:11:50

@robert-stuttaford: I think i'm trying to have the cake and eat is as well :disappointed:. Take the following example:

(defmacro foo [bar]
  `(fn [x#]
       (+ x# ~(:x bar))))
Now, (foo {:x 10}) compiles, but (let [bar {:x 10}] (foo bar)) does not (because bar is just a symbol inside the macro). A solution would be to make foo a function and use eval on the result, but for reasons I cannot use eval.

hellofunk11:11:43

moxaj: try this: (defmacro foo [bar] `(fn [x#] (+ x# (get ~bar :x))))

hellofunk11:11:08

sorry new to slack didn't format that right ;( but you need to reference bar directly before acting on it, and this works

hellofunk11:11:41

or you could just do (:x ~bar)

moxaj11:11:39

@hellofunk works, but I'd like to 'inline' (:x bar) into the body of the function to avoid looking it up everytime the function is invoked

moxaj11:11:51

@hellofunk thus the outer ~

hellofunk11:11:56

you have no choice but to look it up at runtime. there is no value of bar at compile time, right

hellofunk11:11:25

remember, your macro is running and returning new code before your program even runs

moxaj12:11:25

@hellofunk I guess i'll have to return to eval and somehow make it run on clojurescript as well (which is complicated)

hellofunk12:11:22

@moxaj don't do that!

hellofunk12:11:36

@moxaj never use eval unless you have no choice.. and here you have many other choices

hellofunk12:11:05

@moxaj the entire idea behind clojure involves looking up data in collections, so I'm not sure why you don't want to do this at runtime, that is kinda the underlying point of the language.

moxaj12:11:55

@hellofunk I'd like to generate functions for user provided 'schemas', and the performance of these functions is a major concern

hellofunk12:11:53

@moxaj: and you have strong evidence already that the very basic process of lookin up a value in a clojure map, which is fundamental to the entire language, is a performance problem for you?

moxaj12:11:54

@hellofunk well, i'm trying to squeeze out whatever I can, so if possible i'd like to avoid lookup up those keys for the millionth time, since it's already known at compile time (and here lies my problem, it's not exactly known, wrapping it in an identity or something like that can break it..)

hellofunk12:11:11

@moxaj: you are unnecessarily complicating your work, and you are working against the language. you shouldn't worry about a basic key lookup in map -- thousands of heavy production performance-sensitive apps catering to thousands of users real-time simultaneously around the world are using the core language as it was designed, and so should you. If you feel that strongly about a basic key lookup, I'd say maybe you're using the wrong language :wink:

moxaj12:11:30

@hellofunk it's not that I have something against it - I was simply curious if there was a way to spare it :simple_smile:. And you are perfectly right, this may be completely unnecessary, I was only trying to see how far I can push.

hellofunk12:11:23

@moxaj there will always be ways to make any program faster, there is never a point at which you can say "my program is as fast as possible." therefore, the principle is that you should simply not worry about making your program faster until you have reason to spend your precious development time to do so. concentrate on your big picture ideas first

moxaj12:11:46

@hellofunk I know about the saying "premature optimization is the root of all evil", but when you set off with a goal to make a simple library which is as performant as possible, you can't just say: "alright, now that this thing works, let's see how I can make it faster". Or at least that's not how I was thinking in this case.

hellofunk12:11:13

@moxaj: well, you should be thinking that. :simple_smile: first, make your program actually work, and don't get up caught up on something as simple as a key lookup in a map. that is just not a good use of your brain to worry about. after you make your program actually work and do what you want it to do, and prove to yourself that your idea is effective, then and only then you can question if it is fast enough for you. 99% of the time, it probably will be, because computers are pretty neat little machines :wink:

moxaj12:11:38

@hellofunk yeah, and then there's the jvm, which is a lot smarter than me regarding optimizations, so I may be shooting myself in the foot :simple_smile:. Also I'd like to add that it's not just simple key-value lookups, it's complex functions being called on various parts of the data, which is 'more or less known' at compile time.

hellofunk12:11:06

@moxaj: and how is it that your data is mostly compile time? you just have a bunch of map literals def'd in your source and you reference them?

moxaj12:11:33

@hellofunk well, you say (defconfig something x) where defconfig is a macro of mine and instead of x you put a big fat data structure, and then it proceeds to generate some tailor-made functions for your cases.

moxaj12:11:52

@hellofunk something is just a symbol you pass

hellofunk12:11:12

@moxaj: yes but how can you say with certainty that your data is known at compile time? where is the "big fat data structure" coming from, how is the data itself generated?

moxaj12:11:38

@hellofunk the x is provided by the user. And I cannot say with certainty that the data is known at compile time, which is why I had to resort to eval.

moxaj12:11:28

@hellofunk if the user provides something that evaluates to itself, I'd be happy, but I cannot make that assumption.

hellofunk12:11:47

@moxaj just don't worry about it, and never use eval :wink:

shanth13:11:38

Is there any examples for Telegram Bot? I'm trying to parse webhook POST json.

timvisher13:11:07

are there any really good open source examples of hybrid clojure/clojurescript projects that use the new reader literals or even better use the approach recommended in the docs? > The primary mechanism for managing platform-specific code is to isolate that code into a minimal set of namespaces, and then provide platform-specific versions (.clj/.class or .cljs) of those namespaces.

timvisher13:11:25

the few i'm aware of (prismatic/plumbing) don't use either approach

timvisher13:11:48

automat doesn't as well…

malch13:11:38

or not :blush:

cjmurphy13:11:47

Not really answering your question, but I've used the reader conditionals and it all worked fine.

timvisher14:11:16

:facepalm: core.async of course…

cjmurphy14:11:12

oh - reader literals!

timvisher14:11:29

@cjmurphy: ? :simple_smile:

stuartsierra14:11:40

@timvisher: I used conditional read in the latest release of "Component" https://github.com/stuartsierra/component

timvisher14:11:09

@stuartsierra: thanks!

roelof14:11:55

which ide do you all use. I tried Lighttable but it has it problems.

roelof14:11:35

Also tried cursive but there I could not find out how to add more lein task to the lein task screen

swizzard15:11:29

:disappointed:

malch15:11:17

spacemacs (vim + emacs) :smile:

roelof15:11:30

thanks, enough to study

doddenino15:11:46

emacs (prelude)!

albaker15:11:39

I still use light table - I don't hit any issues on the daily workflow, and still feels very elegant

jstew15:11:55

I like emacs, but I've been using it for everything for many years.

roelof15:11:49

@albaker thanks, my main issue was that some of the error messages stays even if I solved the problem

roelof15:11:49

Second one I could not find out how to do something like lein eastwood within Light table. I do not like that I have to use a seperate terminal for these sort of things

jstew16:11:16

unfortunately, using a separate terminal is a fact of life with most editors. You get used to it though, cmd-tab or alt-tab becomes part of your muscle memory. Having a nice shell like zsh helps, too.

jstew16:11:59

You can run a shell in emacs, but it's kind of clunky so I don't even bother.

roelof16:11:20

bummer :disappointed:

roberto16:11:44

you have to be comfortable with the terminal

roberto16:11:04

clojure is not the only ecosystem where this is the case

roberto16:11:10

node, ruby, python, etc

roelof16:11:23

Then I can better do everything in a terminal like lein repl and friends

roberto16:11:36

use the right tool for the job

roberto16:11:40

editor to edit code

roberto16:11:44

terminal to run commands

roberto16:11:30

when you feel comfortable with that, then start looking into other editors that might give you the ability to do everything (almost) from within its confines.

albaker16:11:33

roelof: I don't mind having a terminal for other lein tasks

roberto16:11:42

but if you are just starting, keep it simple.

roberto16:11:48

editor + terminal

jstew16:11:56

It's important to have a REPL in your editor environment though. Without that, REPL Driven Development would not be possible. I wouldn't run lein repl in a terminal, I would take the time to get the REPL working in your editing environment.

roelof16:11:28

oke, lighttable has some sort of REPL

roelof16:11:07

if I look at http://nitrious.io running lein repl takes a few seconds

albaker16:11:26

yes I use the instarepl in lighttable, and sometimes connect the files for evaluation as well so I can have the full classpath/file to eval/edit as I go.

roberto16:11:43

yeah, I think one of the issues @roelof was having was trying to run lein plugins from within the repl

jstew16:11:47

yes, the startup time is really bad. One reason I always have a repl running in emacs.

roberto16:11:02

something like eastwood, for example

roelof16:11:21

@roberto: correct

roberto16:11:52

yeah, those are lein plugins, you need to run them with lein, from the terminal. Unless you develop a plugin for your editor that does that.

roberto16:11:15

Emacs has some plugins that help you run some lein plugins, but that is very Emacs specific

roberto16:11:32

You might be able to do that with LightTable

roberto16:11:48

but it is something you might have to build for yourself

jstew16:11:37

ah, yeah, lein plugins are a different beast than running the repl. I thought I saw lein repl mentioned earlier.

roelof16:11:40

@roberto: thanks, maybe in the future. Otherwise I have to learn two things , clojure and making light table plugins

roberto16:11:55

keep it simple when you are starting

roelof16:11:05

Thanks all

roelof16:11:23

time for dinner here (17:31 hour)

spei16:11:57

@roelof: I think emacs + cider is fine. I think prelude is a reasonable start distro for it as well (if you don't like spacemacs)

roberto16:11:11

Emacs Live is also another option. http://overtone.github.io/emacs-live/

denis18:11:02

Hello! Just a stupid question: how to add an element to the end of the list? Any simple way? Like (some-f '(1 2 3) 4) -> (1 2 3 4). "conj" adds to the beginning of the list, but when one writes macros it's better to be able to add something to the tail of some expression.

noonian18:11:46

There isn’t an efficient way so Clojure doesn’t make it easy

dominicm18:11:47

concat is usually the answer @denis

jstew18:11:38

Or if possible, use a vector instead of a list

dominicm18:11:05

^^ Although sometimes you end up doing silly things like putting a list into vec, and then conj'ing...

dominicm18:11:16

Which doesn't work out well

denis18:11:17

yes, i did with vect, conj, reverse, into and something else, maybe :simple_smile:

denis18:11:49

but something like this seems to work: (defn some-f [lst el] (concat lst (list el))) ?

noonian18:11:25

concat returns a lazy seq though, which is probably fine but something to be aware of

stuartsierra18:11:27

although be aware that concat returns a sequence, not a list

denis18:11:42

ok, thanks!

denis18:11:56

At least, now I know I didn't miss something

roelof19:11:11

any cursive user here. Is there a way I can extend the lein task list

kidpollo19:11:02

@roelof: there is a channel for that :stuck_out_tongue: #C0744GXCJ

staypufd20:11:25

Hello all - I think I found a bug in update-in, at least according to the docs

staypufd20:11:50

the docs say if any levels do not exist hash-maps will be created

staypufd20:11:57

so for a simple test I did

staypufd20:11:09

(def a {:a 10})

staypufd20:11:22

(update-in a [:b] + 2)

staypufd20:11:34

and I get an exception

staypufd20:11:35

(update-in a [:b] + 2) NullPointerException clojure.lang.Numbers.ops (Numbers.java:961)

juhoteperi20:11:14

@staypufd: Not related to update-in but +. It is called with the current value which is nil and (+ nil 2) throws NPE. You need to use a function which can handle nil value, e.g. (fnil + 0).

staypufd20:11:08

let me try that and see if it creates the hash

staypufd20:11:25

I’m still new to Clojure so making lots of mistakes like this

staypufd21:11:50

So @juhoteperi when I changed it to a function that wasn’t doing something to nil it worked

staypufd21:11:58

(update-in a [:b] print) nil=> {:b nil, :a 10}

staypufd21:11:06

So thanks @juhoteperi

timvisher22:11:16

anyone know what i should reference regarding building a new project.clj file for a clojure contrib project? for now i'm going with core.async :simple_smile:

alexmiller22:11:17

Don't use that one

alexmiller22:11:57

Contribs don't actually use their project.clj at all

alexmiller22:11:01

But async is one of the most customized contrib projects

timvisher22:11:53

@alexmiller: thanks for the feedback! i'm attempting to act on http://dev.clojure.org/jira/browse/DPRIMAP-8. i think i need to add cljsbuild to be able to test it. i think my only option is project.clj?

timvisher22:11:52

maybe tools.reader is a better example?

alex.nixon22:11:36

does async have an equivalent of 'cat'? I have n channels (c_0, c_1, ..., c_n), and I want to produce a channel C which is the concatenation of all c_0's events, followed by c_1's, etc

alexmiller22:11:06

@timvisher: yes you will need a project.clj for that. And yes tools.reader is a better example.

timvisher22:11:20

@alexmiller: :metal:

alexmiller22:11:53

Projects like tools.reader support Clojure versions older than 1.7 and do not use cljc

alexmiller22:11:52

So, going that direction means dropping support for older Clojure versions

alexmiller22:11:19

That should not (yet) be done lightly

alexmiller22:11:27

The only contrib that has moved to cljc is is test.check so that is the best example for that

alexmiller22:11:18

Cljc requires a newer version of the Clojure maven plugin which requires a newer version of maven than is supported by the contrib ci server. This is a problem I have been working on.

timvisher22:11:19

@alexmiller: oh that's interesting. i hadn't considered the back porting. it doesn't appear to me that data.priority-map as of yet has any testing for prior versions or really any testing declared at all?

timvisher22:11:23

is that all done in jenkins?