Fork me on GitHub
#clojure
<
2017-11-17
>
vemv00:11:52

@rcolyer sorry to hear about RSI 😞 I've owned those mentioned Microsoft and Kinesis in the past (circa 2011). I found them dangerously misleading - I've used Apple keyboards since 2013 - zero pain now, zero contortions (un-natural movements)

vemv00:11:24

I have used Emacs this whole time. It hasn't been a factor of pain, given that since day one I rejected the emacsy way of using the keyboard. all my shortcuts are in the form: command-s ctrl-a alt-e etc. simple stuff. particularly good that one can use three modifiers easily, in Mac

vemv00:11:11

you may read a little about my approach (and my real list of shortcuts) in https://github.com/vemv/.emacs.d . my config is not shareable as of today, but I'm working towards that. anyone interested can ping me

vemv00:11:44

--- in general I think I have quite a story to tell, about how I beat wrist pain. Like, it really hurted a few years ago, felt how my career was at risk. did lots of research and found some really good advice buried in a sea of workarounds. as a sad trivia, the only people I've ever met with RSI (or similar) were clojure programmers. and I couldn't really share my advice with them, because normally you can't tell people they're just wrong

vemv00:11:57

--- this "good advice" is a bit complex to tldr, I guess I could record a 20m video for anyone interested

ericnormand04:11:11

is there a way to alias a namespace without requiring it?

andy.fingerhut04:11:22

Maybe clojure.core/alias can do that? Not sure.

andy.fingerhut04:11:25

e.g. (alias 'str 'clojure.string) followed by (doc str/join) gives docs for clojure.string/join

Alex Miller (Clojure team)04:11:29

that’s a red herring - clojure.string is loaded during startup. alias requires the namespace to be loaded to be able to alias it. So the answer to the original question is no. But you can work around that with a call to create-ns first

qqq04:11:21

I have a naming question. I am genuinely tempted to mix camelCase with - . Here is the problem> Suppose I have an object, say update-event then, I have other functions: update-event-new update-event-process update-event-do-foo-bar but then it's not clear to me where the "noun" and the "verb" are separated. Whereas, if I named my event updateEvent then I ca ndo updateEvent-new updateEvent-process updateEvent-doFooBar however, Clojure seems to uniformly dislike camelCase

qqq04:11:26

oh wait, Protocols use camelCase -- so it's actually acceptable right?

Alex Miller (Clojure team)04:11:22

Clojure doesn’t care what you do, but other people might :)

qqq04:11:52

right, by "Clojure" I meant to say "Clojure Community"

Alex Miller (Clojure team)04:11:23

why do you need to repeat “updateEvent” in all those names?

qqq04:11:24

it seems like the Protocol naming convention sets precedence that it's 'okay to have camelCase for multi word nouns"

Alex Miller (Clojure team)04:11:43

protocols create Java interfaces under the hood so they steal Java style naming

Alex Miller (Clojure team)04:11:03

or at least many people follow that

Alex Miller (Clojure team)04:11:25

you only really refer to protocols by name when you implement them though

Alex Miller (Clojure team)04:11:00

most clojurists do not use camelCase for nouns, they use kebab case

qqq04:11:47

I have a lot of functions of type signature verb :: foobar -> ... -> ... -> ... -> foobar so I like to have functions of name foobar-verb1 foobar-verb2 foobar-verb3 when 'foobar' and 'verbi' both contain dashes, I find it awkward to read

qqq04:11:25

some-noun-name-do-action-one vs someNounName-doActionOne

Alex Miller (Clojure team)04:11:58

that seems more verbose than most clojure code

Alex Miller (Clojure team)04:11:14

why not just (defn verb1 [foobar])

qqq04:11:49

@alexmiller: the suggestion there seems to be lots of small namespaces, and not repeat namespace name

ericnormand04:11:39

I like his suggestions

ericnormand04:11:50

I don't think I've ever used camelCase in Clojure

ericnormand04:11:11

I also prefer verbs in front

ericnormand04:11:21

like a command/imperative

ericnormand04:11:00

but when I see what you've written above, the first thing that pops into my head is "that's a namespace"

ericnormand04:11:28

that is, a common prefix for top-level definition names

ericnormand05:11:17

but the nice thing is it splits the two pieces with a different character, /

ericnormand05:11:33

that could solve the readability issue you're having

dominicm09:11:16

I think I'd solve it how the CSS people do: update-event--new. But I'd also avoid this problem in the first place by not doing this.

andrea.crotti10:11:49

I'm writing some "scripts" that will help to check a few things like status of database tables or marathon tasks for example

andrea.crotti10:11:36

the scripts now simply do log/error on errors and log/info otherwise, however it would be also nice to keep track of all the errors in a data structure

andrea.crotti10:11:08

(which is computed across different functions), and exit with failure Exit code in case anything failed

andrea.crotti10:11:49

any suggestions about how to do that?

andrea.crotti10:11:21

the easiest way would be to use an atom maybe, but it would have to be shared across different namespaces or being passed in from core.clj

njabsoul10:11:03

Hi guys I need your help. I want to make a clojure query, but the :where conditions are condition. SO i used cond->. this works well. but now my problem is that I want to make a clojure function call inside a (‘) or quote. (defn foo [num] (inc num)) (def query ‘[:find ?e :in $ :where ]) (cond-> query (some-condition) (conj ‘[? :data/number ?number]) (some-other-condition) (conj `[’(&gt; ?number (foo 2))])) I get this result: [:find ?e :in $ :where [? :data/number ?number] [(> ?number (clojure.core/unquote (foo 2)))]] What I am trying to achieve is this: [:find ?e :in $ :where [? :data/number ?number] [(> ?number 3)]] Can anyone please help

madstap11:11:08

This will work:

(cond-> query
  (some-condition)
  (conj '[? :data/number ?number])
  (some-other-condition)
  (conj `[(~'> ~'?number ~(foo 2))]))
You could write a little helper function to make this easier though.
;; NB: Only use this when you specifically want a list (ie. code).
;;     Normally prefer using conj on a vector.
(defn append [coll & xs]
  (concat coll xs))

(cond-> query
  (some-condition)
  ;; This is probably supposed to be ?e and not just ?
  (conj '[?e :data/number ?number])
  (some-other-condition)
  (conj [(append '(> ?number) (foo 2))]))

xtreak2910:11:02

In clojure I do same transformation to the var and then want to store the result by same name. Is this ok to do so? I don't want to invent new var names for this. Eg. (let [address (cleanup address)] address)

madstap12:11:02

That's fine. It's a local though, and not a var. Vars are the things that def and defn create at the top level. You shouldn't define those more that once (except at the repl, when developing).

thedavidmeister11:11:38

why do i get an invalid number exception for 0x1.0p-53?

bronsa11:11:03

because that's not a valid clojure number literal

thedavidmeister11:11:12

but it works in java

bronsa11:11:18

and it doesn't in clojure

bronsa11:11:21

they have different lexers

thedavidmeister11:11:44

clojure docs say "As of version 1.3, Clojure provides full support for JVM primitive values, making it possible to write high performance, idiomatic Clojure code for numeric applications."

bronsa11:11:11

and that's true

bronsa11:11:19

what it doesn't say is that clojure will accept all java literals

bronsa11:11:27

because it doesn't

thedavidmeister11:11:42

so if it did accept more literals for primitives, you wouldn't say that support for primitives has been improved?

Alex Miller (Clojure team)14:11:45

Feel free to file a ticket - Java has added stuff over the years and I don’t see any reason we shouldn’t track their literal

michaellindon15:11:53

Hi everyone, I have an interview coming up for which the recruiter told me to prepare for datastructures questions. I know I should review them, but I'm loathed to learn about mutable versions as I never use them anymore 😕 Id much rather learn about immutable implementations so that at least its relevant to my interests. How come there are so many tutorials for mutable but not immutable datastructures

michaellindon15:11:26

Moreover, its actually not natural to create a mutable datastructure in clojure i find

nha15:11:58

All I remember is that Clojure uses something called HAMT

nha15:11:25

(IIRC - a bit fuzzy on this, although I did some reading a long time ago)

nha15:11:28

The comment is actually pretty clear

michaellindon15:11:26

Thanks @nha looks good

michaellindon15:11:41

I'm thinking more along the lines of if asked to implement a binary tree, how would i implement a persistant version

nha15:11:08

oh right. I think I did something like that on.. codewars maybe?

nha15:11:22

They have two “katas” that make you implement these IIRC

nha15:11:49

But I agree overall, there is a gap in knowledge about these immutable data structures

michaellindon15:11:22

This looks great 🙂

michaellindon15:11:27

i wish there were more like this

michaellindon15:11:37

but yes this is the sort of thing im looking for

nha15:11:19

Definitely 🙂 If you come across some more I would be interested to hear about it 😛

leontalbot17:11:59

Hello! Are there libraries that manipulate plain datastructures in the fashion of Datomic pull syntax?

leontalbot17:11:21

I saw this, but seems not quite alive

jeff.terrell20:11:28

3 days ago, @fabrao and @reborg had an exchange about transduce-ing a transformation. I found the exchange interesting and helpful for learning transducers, and I thought it might be useful to stick it somewhere more enduring than this Slack channel. So, with their permission, I wrote it up and posted it to StackOverflow [1]. One of the side benefits is to have more Clojure content on StackOverflow, which will help us look better next time they analyze languages. I welcome others to similarly capture interesting or useful content from here to StackOverflow. (Or even go the other way and post a question there first, linking to it here.) Totally voluntary, of course, but I think it might benefit our broader community. Cheers! [1] https://stackoverflow.com/q/47358416/202292

borkdude21:11:05

Starting to like transducers are lot now: https://stackoverflow.com/a/47354316/6264

borkdude21:11:29

I’m wondering on which kind of things you can apply them also, instead of collections, text files, SQL results?

didibus21:11:38

When files are loaded, when does macros expand? Would my macros expand before earlier def ? And in my case, before earlier spec s/def ?

didibus21:11:58

Or do they expand in parralel?

hiredman21:11:46

the compilation unit for clojure is a form

hiredman21:11:23

so a single form is compiled to bytecode at a time, and macroexpansion needs to happen before bytecode can be generated, so macroexpansion is a form (a top level form, at a time)

didibus21:11:36

Oh, ok, and in order from top to bottom in the file, and then for each top level form, it goes inner form to outer form?

hiredman21:11:06

macro expansion happens outer to inner (I could mixing this up, but I don't believe I am)

didibus21:11:47

Oh right, I think I remember that

hiredman21:11:58

this is way something like (when-let (some-macro-that-expands-to-a-binding-vector) ...) doesn't work

didibus21:11:49

Ya, I guess it does, when you have a macro inside another, and call macroexpand-1, you only see the outer one expanded.

didibus21:11:19

I'll get us back on topic, why is it discouraged to wrap macros in functions to allow to compose them?

seancorfield21:11:54

The guidance I've always felt I got from the Clojure/core folks was: always write functions first, then use macros only to provide syntactic sugar (or to achieve something that is impossible in a function -- but even then, use the macro to translate it to a function call).

didibus21:11:48

A use case I find commonly is I want to extend an existing macro. So I want to maybe transform the input to the macro, before sending it to the macro. I can't, because I can't evaluate the args to the macro, so I'm always stuck having to write a macro that wraps the other macro.

borkdude21:11:38

A lot of macros can also be replaced by passing functions instead of a body I think

borkdude21:11:46

Not that it’s convenient, but you can. I mean the with- kind of macros which is 90% of the macros I write.

didibus21:11:19

Hum, that's true, or can be written like that if you take thunks as the predicates

seancorfield21:11:35

> I'm always stuck having to write a macro that wraps the other macro Right, because "macros don't compose". If a macro really is just a thin syntactic wrapper to a function, then you can compose functions and then write just a thin veneer macro around it -- wrapping the functionality, not the other macro.

didibus21:11:19

Ya, and I've trying that more so now, to have my macro implementation be full of normal functions, and the macro just does the unorthodox composition of them. But I think when you want to extend a macro in some other lib, like a core macro, its more confusing to me, though maybe I need to just start digging into those * functions inside, and see that I can use those directly or within my macro, avoiding the need to wrap the macro.

didibus21:11:05

I guess I'm trying to understand why macros don't compose. Could they compose? Is there other constructs out there that are different to macros, yet offer similar benefits but also compose

dpsutton21:11:39

what core macro have you wanted to extend?

didibus21:11:02

Well, right now I extended s/keys from clojure.spec

didibus21:11:17

That's what got me thinking

didibus21:11:01

All I do is (s/and the spec from s/keys and another predicate that needs the same input to s/keys.

jeff.terrell21:11:36

Macros are all about the evaluation model. If you understand that, you will know how they can compose. I've written about this here, in case it's helpful: http://blog.altometrics.com/2016/04/a-few-tips-for-writing-macros-in-clojure/

didibus21:11:15

Cool, I'll give it a read.

borkdude22:11:33

I.e. you cannot pass them around as values like you can with functions.

didibus21:11:37

And I was like, why can't this be a function, and its because I can't pass the arguments to a function to the s/keys macros

seancorfield22:11:35

This is a specific case where the implementation of the macro is just wrapped around a function. Alex has acknowledged that and has said a more programmatic API is coming. This is just alpha at the moment.

didibus22:11:32

Oh, that's pretty good to know.

didibus22:11:18

I guess I've been reading a bit about rebol: http://blog.hostilefork.com/rebol-vs-lisp-macros/

didibus22:11:56

And I've noticed that one of the limitations of macros from composing in Clojure is that they evaluate at compile time. They act like a pre-processor, and don't have runtime context.

didibus22:11:36

And so, you can pass quoted code to functions, and then the function can choose to eval it, but eval also runs without context, so the code you pass quoted does not carry an environment, all bindings are lost.

didibus22:11:31

But why doesn't Lisps also allow a way to pass code with its environment, like Rebol does? It seems like it could be an interesting thing.

seancorfield22:11:35

This is a specific case where the implementation of the macro is just wrapped around a function. Alex has acknowledged that and has said a more programmatic API is coming. This is just alpha at the moment.

didibus22:11:00

Now, functions can be passed with an environment, but they can't be transformed before being evaluated, so again its limiting in some ways.

didibus22:11:45

Ya, it might be overkill, and having all these different meta programming construct could get confusing and make things worse, but I'm having fun thinking about it 😛

noisesmith22:11:41

sometimes a good answer is to make a macro that returns a function - the function captures your locals nicely and lets others pass in values

noisesmith22:11:22

it tends to elegantly solve the “I would use eval but it loses context” issues if you generate functions and pass in the locals

didibus22:11:07

I'll have to think about this

noisesmith22:11:56

it looks like (let [some-f (eval form-for-f)] (some-f local1 local2))

didibus22:11:06

Interestingly, it appears this is an old idea called FEXPRS, and people talk about it: http://wiki.c2.com/?RuntimeMacro and https://en.wikipedia.org/wiki/Fexpr

noisesmith22:11:16

yeah, they are very very slow

noisesmith22:11:25

they mean you need interpreted instead of compiled code

didibus22:11:40

Ya, I can see that, as there is no way to know the order in which things will end up at runtime

qqq22:11:29

It appears that I can use a qualified keyword for a namespace that: 1. does not exist 2. exists in project, but is not yet loaded (to avoid circular dependency) Are there any gotchas I should be aware of concerning these ?

seancorfield23:11:31

The only "gotcha" I can think of is when you use something like ::alias/name and it will depend on having the alias defined as an alias for the actual namespace qualifier.

dpsutton23:11:37

yeah and the errors from the alias not existing are terrible

dpsutton23:11:08

copying aliased stuff into a ns without an alias throws like 5 reader errors in succession

qqq23:11:48

ah, but since I'm not requiring the namespace (to avoid circular dependency), I'm doing :foo.bar/kw-name

qqq23:11:57

I don't see where the ::alias/name would show up

dpsutton23:11:13

its if you explicitly use it

dpsutton23:11:23

if everything is namespaced by :Account/permissions and :Account/username it can get a little tiring, and your code can get a little wide. So its nice to use

(create-ns 'HumanName)
(alias 'HN 'HumanName)

seancorfield23:11:00

Yeah, we have ws.domain.member and usually alias that to m so we have ::m/id etc instead of :ws.domain.member/id

qqq23:11:43

I still do not understand how this applies to the current question, but when I run into this issue, I'll look back at this.

dpsutton23:11:34

they are just gotchas with namespace qualified keywords