Fork me on GitHub
#clojure
<
2016-12-12
>
shaun-mahood04:12:26

@quoll I just listened to your interview on the most recent Cognicast - I think it makes the perfect companion to your Conj talk, there was a lot of great information in both that complemented the other. As someone who had no idea what semantic web or rules engines were 2 weeks ago, it was a pretty comprehensive intro and I think I may even have some future work that might benefit from one. Thanks!

quoll05:12:08

You're welcome. I'm glad you liked it 🙂

Aron09:12:18

i find the lack of good random graph generators in clojure surprising, perhaps i am just not finding it. anyone knows implementations of the Barabasi-Albert or even better the Holme-Kim generator? Or something that can generate scale-free networks at least?

Aron09:12:56

guess is should just write it or use it from javascript

alexisvincent11:12:22

is the general consensus to prefer namespaces keys in maps?

wilkerlucio12:12:00

@alexisvincent yes, this is one of the hot topics, specially since clojure.spec, you should prefer namespaced keywords, unqualified keywords are still good for more local things

alexisvincent12:12:25

@wilkerlucio This seems to be the way spec nudges you. Shot

wilkerlucio12:12:34

it's a good thing, global long namespaced names can be shared across applications and libraries, think that on long term you will be able to re-use specs like you do with functions, and even better, imagine just by using the correct keyword as key you get the data validation for free 🙂

tbaldridge12:12:57

it also encourages you to use a single flat map instead of many nested maps. Now :person/name can exist in the same map as :car/name and :pet/name, and :data.importer/name, no longer a reason to have three separate maps.

tbaldridge12:12:16

@alexisvincent what's your concern with namespaced maps?

alexisvincent12:12:50

that is nice 🙂 I feel like it limits refractorability. Unless the clojure refractoring tools are good? Im new to the language

alexisvincent12:12:11

Im concerned that if I overqualify things Im going to give myself a hard time later when I want to better structure my code. Im new so this is an inevitability

gfredericks12:12:05

@alexisvincent: namespaces of keywords can be independent of namespaces of code

gfredericks12:12:43

so at worst your code might be a bit more verbose to continue referencing the old keyword-namespaces

alexisvincent12:12:38

except if you’re using :: everywhere, this would break if you moved things…?

gfredericks12:12:46

that's what I meant by the code being more verbose -- you'd have to change those

gfredericks12:12:30

so it doesn't limit refactorability, but it might limit your appetite for refactoring :)

alexisvincent12:12:14

"but it might limit your appetite for refactoring :)” thats what I meant xD

alexisvincent12:12:48

I’m building a system where namespaces look like this shipping.parcel, should I not use the :: helper with spec? It’s a pain specifying :shipping/* everywhere

alexisvincent13:12:45

OH 🙂 :: can also be used for aliasing

wilkerlucio13:12:46

@alexisvincent the support for refactoring is very good on Cursive, it always worked for me when I need to rename keywords

alexisvincent13:12:28

@wilkerlucio I’ve just switched from cursive to trying cider with spacemacs

alexisvincent13:12:41

enjoying the experience so far

wilkerlucio13:12:34

nice, just use what feels better for you 🙂

wilkerlucio13:12:47

@alexisvincent about the namespaces, I discussed with some people at Conj and this seems to be a common pattern: use fully qualified namespaces for library code (code you intent to share with other people, so long names like company.core.model/name) and single namespace for domain data (like :shipping/name :user/name)

alexisvincent13:12:20

@wilkerlucio this does make sense 🙂 I kinda have the best of both worlds with the current aliasing approach

wilkerlucio13:12:24

I would like some better aliasing, you can do on clojure, like: (create-ns 'shipping.parcel) then (alias 'sp 'shipping.parcel), after that you can do ::sp/whatever, just keep in mind this doens't work on clojurescript

tbaldridge13:12:41

and as mentioned, if you do (:require [foo.bar :as b]) you can then later do ::b/name and that will expand to :foo.bar/name

alexisvincent13:12:01

Thanks guys. Thats helpful

alexisvincent13:12:27

Im keen on the aliasing method. Flexible and doesnt clutter the namespace

tbaldridge13:12:13

@wilkerlucio there's several Clojure tickets asking for that, I think the current status is that they need some hammock time since there's no reason this needs to be tied 1:1 with Clojure namespaces.

tbaldridge13:12:22

But I want that feature too.

wilkerlucio13:12:35

@tbaldridge yes, that will make using long namespaces a non brainer, after that I would be happily willing to use long names for domain data 🙂

alqvist14:12:33

What is the best way of namespacing an existing map? Using a function, not the reader. Keys are unknown

alqvist14:12:56

I could use

reduce-kv
or something, but it feels wrong

jcromartie14:12:49

alqvist: everybody writes a "map-keys" function at some point 🙂

jcromartie14:12:53

I don't think there's a right answer

jcromartie14:12:05

I sometimes just do (into {} (for [[k v] m] ...))

jcromartie14:12:25

and there are plenty of libraries that make transforming maps easier

jcromartie14:12:53

like specter

alqvist14:12:55

jcromartie: I went with

(defn qualify-map [namespace m]
  (reduce-kv #(assoc %1 (keyword namespace (name %2)) %3)
             {} m))

alqvist14:12:08

I don't like it though 😕

jcromartie14:12:16

it looks fine to me

jcromartie14:12:29

honestly I don't understand the point of reduce-kv over plain old reduce

jcromartie14:12:35

is it a performance thing?

val_waeselynck14:12:07

@jcromartie the existence of clojure.lang.IKVReduce is a hint that yes

jcromartie14:12:14

yeah, I'd assume

jcromartie14:12:58

I looked at the source of reduce-kv quickly but it just calls a protocol function of course

Alex Miller (Clojure team)14:12:07

Hey all, the 2016 State of Clojure Community survey is now open! We do this every year as a way to take the pulse of the community and if you can spare 5 minutes to take it, it would be awesome to get input from everyone here. https://www.surveymonkey.com/r/clojure2016

pesterhazy14:12:30

@jcromartie it's definitely faster in many cases than pure reduce

alqvist14:12:36

jcromartie thanks for your answer

jcromartie14:12:29

I think your solution is going to have good performance. Maybe just use a full (fn [m k v] ...) instead of a #(...) for clarity?

alqvist14:12:01

jcromartie: Wooah take it easy now, I don't want to be replaced just because someone could understand my code 😛

alqvist14:12:20

job security = write only code

alqvist14:12:39

(have my own company though, so maybe it is moot)

jcromartie14:12:56

BTW with specter, it looks like this

jcromartie14:12:18

(defn qualify-map
  [namespace m]
  (transform [ALL FIRST] #(keyword namespace (name %)) m))

tbaldridge15:12:16

I think this is about as fast as you can get: (defn qualify-map [ns mp] (persistent! (reduce-kv (fn [m k v] (assoc! m (keyword (name ns) (name k)) v)) (transient {}) mp)))

jcromartie15:12:40

@tbaldridge I would assume that the various protocol implementations for reduce-kv use transients

jcromartie15:12:15

but it might be a bad assumption!

nathanmarz15:12:24

@tbaldridge actually, for small maps (PersistentArrayMap) it's faster not to use transients

tbaldridge15:12:39

@jromine transients are for updating collections reduce-kv doesn't update anything

jcromartie15:12:39

I may be way off here but I could imagine an implementation of reduce-kv that starts with a transient version of the initial map

jcromartie15:12:57

but no, I see what you mean

jcromartie15:12:02

it's not associng anything

jcromartie15:12:07

it's entirely up to the fn you pass in...

mikerod16:12:10

Does anyone know where I can get more background on org.fressian.impl.InterleavedIndexHopMap which is used by Clojure Fressian serialization?

mikerod16:12:24

I search for these sorts of words online and am not getting anything good

mikerod16:12:03

I just wanted to get some background one what it’s about. Obviously I can just read the implementations, but not sure that’ll show me the real reasoning behind the choice. (I guess theoretically I could figure it out 😛 )

ghadi16:12:02

@mikerod it's a hashmap that uses open-addressing, and the InterleavedIndexHopMap describes how to deal with collisions

ghadi16:12:21

I think @stuarthalloway could probably help with rationale/impl

alandipert16:12:01

anyone aware of a cfg parser generator a la instaparse, but for parsing clj data instead of strings?

dominicm16:12:04

@alandipert rewrite-clj has done the work you want, I think

dominicm16:12:14

The parse namespaces in rewrite-clj are VERY good.

dominicm16:12:41

Compared to "just" tools.analyzer anyway.

mikerod16:12:30

@ghadi thanks, yeah I plan to read through the impl to try to get a better idea

mikerod16:12:42

I was just wondering if it was based on some paper somewhere or something like that to get some quick background

alandipert16:12:29

@dominicm thanks, i'll give it a look

radon16:12:46

Leiningen seems to be remembering which dependencies I have used in the past. I do

$ rm -rf ~/.lein ~/.m2
$ lein repl
and it downloads all the dependencies in my profiles.clj (which no longer exists). Are there any other caches I need to clear? This behavior does not reproduce on a virtual machine with a fresh install of macOS and Leiningen. I have also tried
$ brew uninstall leiningen && brew install leiningen
to no avail. I am not running any of the above from inside a Clojure project.

jcromartie16:12:40

after brew uninstall leiningen

jcromartie16:12:58

can you check to see if which lein finds anything?

radon17:12:49

Nope, doesn’t find anything.

hiredman17:12:01

the simplest explanation for lein downloading deps specified in your profiles.clj is your profiles.clj still exists

radon17:12:16

Well it’s pretty hard to argue with rm -rf ~/.lein.

radon17:12:23

Is there an alternate location that could have a copy?

radon17:12:05

Wait, I heard something about a system-wide profiles.clj a while ago…

hiredman17:12:07

and are you running lein repl in a filesystem subtree that has a project.clj or profiles.clj somewhere above it?

radon17:12:29

It doesn’t download the deps when I’m in the root directory. I bet that’s it.

radon17:12:40

Well, I feel stupid. Yes, there is a profiles.clj.

radon17:12:54

Right, because you can have them local to a project.

radon17:12:02

So it’ll pick them up from anywhere above your current directory.

jrheard17:12:38

re: namespaced keys, at an old job we once spent like a couple of years first realizing and then untangling the fact that our python webapp had a ton of code that read self.country and did various things based on it

jrheard17:12:57

and a slightly smaller amount but still medium amount of code that set self.country and performed some side effect

jrheard17:12:37

(with great method names like self.set_country_and_maybe_redirect(args)) - i have learned to be terrified of things with names like foo_and_maybe_perform_side_effect()

jrheard17:12:07

but anyway so what i’m getting at is that it took us a while to realize that there were different kinds of country, and to notice that different corners of the codebase were setting self.country and reading self.country with their own interpretations

jrheard17:12:04

so this third of the codebase treated self.country as the country of the business that was currently being viewed by a user, and this other third treated it as the country associated with the user’s account, and this other third treated it as the country associated with the web interface’s locale

jrheard17:12:39

and so if you were trying to reason about how page X would behave if a logged-in user was viewing a business in france and the user’s home country was set to england and they were viewing it in the en_US locale....

jrheard17:12:34

anyway we (mostly) got rid of self.country when we realized how messed up the situation was, and started instead just explicitly passing around things like business[‘country’] or interface_locale.country, etc

jrheard17:12:12

and all this flashes through my head whenever i think about regular keys vs namespaced keys - a lot of hassle could have been avoided if we’d eg used :business/country from the start rather than :country

jcromartie17:12:55

namespaced keys are a wonderful thing

robert-stuttaford18:12:21

@pesterhazy does https://github.com/pesterhazy/boot-fmt have a lein equivalent that you know of? pretty cool!

pesterhazy18:12:43

@robert-stuttaford , yeah boot-fmt works irrespective of the build tool, especially with the --git option

pesterhazy18:12:47

There's also lein-zprint by the original author of zprint

alexisvincent18:12:26

Choosing a http server lib. Any suggestions? I’ve seen ring mentioned a lot.

shaun-mahood18:12:29

@alexisvincent: Have you got specific requirements, or just anything to get started?

alexisvincent18:12:35

@shaun-mahood Not so bothered about super quick starting. Want something powerful and elegant, that’s generally made good design decisions. So far I’ve been really impressed with the clojure package ecosystem so I have high hopes 🙂

02b88fc618:12:52

@alexisvincent I would say that http-kit is good. It is evented (NIO). It uses ring underneath. You can quickly add compojure for routing and get running within minutes.

02b88fc618:12:49

Another option would be jetty.

alexisvincent19:12:59

@kadaj So not pure ring?

jcromartie19:12:17

@alexisvincent Ring is not a server, it's a convention for request and response data

alexisvincent19:12:22

Oh interesting. Thats what libs mean by ring-compatible

jcromartie19:12:06

yeah, it's similar to the role of Rack in Ruby

alexisvincent19:12:25

Never done Ruby dev

jcromartie19:12:43

http-kit is a great choice, and another common choice is ring-jetty-adapter

alexisvincent19:12:58

http-kit it is 🙂

alexisvincent19:12:05

and compojure?

jcromartie19:12:16

yes, compojure for routing Ring requests to your particular handler functions

jcromartie19:12:47

compojure lets you build functions that respond to Ring requests, http-kit or ring-jetty-adapter connect those handler functions to a HTTP server

jcromartie19:12:19

unless you are using special features of the servers you can swap any Ring-compatible server for another and keep your handler functions the same

alexisvincent19:12:55

Thanks guys. The Clojure community is honestly the best I’ve ever experienced. Always tons of people to help. 🙂 Its really cool.

jcromartie19:12:44

I'm glad you feel welcome

alexisvincent19:12:04

If i’m in cider, is there a quicker way of reloading the repl with new libs then restarting cider?

dpsutton19:12:39

best i know of is ,restart in the repl

dpsutton19:12:12

and i'm assuming project deps in your project.clj file, rather than deps of a particular file that already exist in the project

camdez19:12:44

@alexisvincent: are you using clj-refactor? I always add my new dependencies through it (`C-c RET a p` — cljr-add-project-dependency) and it magically loads things into the running environment.

camdez19:12:03

Magic to me, anyway. 🙂

dpsutton19:12:05

oh wow, was not aware of that

tbaldridge19:12:16

@alexisvincent I'll throw Pedestal into the ring (pardon the pun) for you: http://pedestal.io/

tbaldridge19:12:44

It's quite simple to get going and has a ton of features not seen in other Clojure http servers

alexisvincent19:12:13

@dpsutton yeah in project.clj. @camdez yeah I amm, thanks! @tbaldridge Shot, thanks 🙂

camdez19:12:05

@alexisvincent: Sweet. clj-refactor is like having superpowers.

dpsutton19:12:48

i'm gonna study up on that more

alexisvincent19:12:52

its great stuff 🙂 Spacemacs also makes discovering stuff you can do really easy

dpsutton19:12:59

i know i've used some common libs and it'll put the requires in for me

dpsutton19:12:09

like s/join-with and it includes clojure.string :as s

camdez19:12:13

@dpsutton: yep, and you can extend that however you like with your own stuff. But that’s using core / things are that already loaded. But cljr-add-project-dependency will browse libraries and pull them into your project.

camdez19:12:31

Definitely. Saves time.

isaac_cambron22:12:39

I don't think I understand what declare really does:

user=> (declare foo)
#'user/foo
user=> (def f foo)
#'user/f
user=> (def foo inc)
#'user/foo
user=> (foo 1)
2
user=> (f 1)

IllegalStateException Attempting to call unbound fn: #'user/foo  clojure.lang.Var$Unbound.throwArity (Var.java:43)
Why doesn't that work?

bfabry22:12:15

@isaac_cambron the second argument to def is evaluated when you call it

bfabry22:12:34

which is generally true of arguments to calls in clojure. in function calls it's always true for all arguments, in macro calls (as def) it's usually true for some

isaac_cambron22:12:40

i see, so since its value is unbound-thing that's now just f

isaac_cambron22:12:44

ok, i can see that

isaac_cambron22:12:08

any ideas on how to work around this? Specifically, I have a map of keyword -> fn and a function -- let's call it foo -- that looks up functions by keyword and calls them, like (foo :do-a-thing). But I'm trying to add a key/fn to that map that composes foo, so I'm in the awkward position of having my map and foo have a circular dependency. I could just mutate the map after I define foo, but it seems like there should be an cleaner way

bfabry22:12:52

declare the map, define foo, define map

jcromartie22:12:00

@isaac_cambron

user=> (declare foo)
#'user/foo
user=> (defn bar [x] (foo x))
#'user/bar
user=> (def foo inc)
#'user/foo
user=> (bar 42)
43

bfabry22:12:14

boot.user=> (declare memap)
#'boot.user/memap
boot.user=> (defn foo [kw]
       #_=>   (kw memap))
#'boot.user/foo
boot.user=> (def memap {:foo foo})
#'boot.user/memap
boot.user=> (foo :foo)
#object[boot.user$foo 0x367f8e91 "boot.user$foo@367f8e91"]

bfabry22:12:22

arguments to things are resolved/evaluated, but function bodies are not, so declare works there

isaac_cambron22:12:47

@jcromartie @bfaber yup, those both make sense. Thanks!

bfabry22:12:04

this is basically what `declare was meant for, function bodies, ie so you don't have to define your functions in a specific order

isaac_cambron22:12:47

Yeah, the problem was that the way I thought about it wasn't differentiating the second value of def from function bodies

isaac_cambron22:12:07

Sort of funny that you can spend this much time writing code in a language without really thinking through precisely how it works

bfabry22:12:40

yeah honestly I never really thought about it either