Fork me on GitHub
#clojure
<
2018-04-18
>
Garrett Hopper02:04:13

Is it possible for me to have a spec: s/cat regex where latter parts of the regex use predicates that depend on the conform of prior parts?

seancorfield02:04:47

@ghopper Can you be a bit more specific about what you're trying to achieve? My first reaction is to suggest s/and wrapped around s/cat and use the predicates there.

Garrett Hopper02:04:23

Whoops, sorry. I guess I only sent this on #clojure-spec.

seancorfield02:04:11

(s/and (s/cat :starts-with string? :values (s/* string?)) (fn [{:keys [starts-with values]}] ...))

Garrett Hopper02:04:39

Oh, nice! I didn't realize s/and would pass the conformed value to the second function.

Garrett Hopper02:04:55

That's awesome. 🙂 Thanks, @seancorfield!

Garrett Hopper03:04:13

@seancorfield I don't suppose there's a way to do this without it starting a new scope?

(s/conform (s/+ (s/and (s/cat :a string?
                              :b string?)
                       (constantly true)))
           ["testa1" "testb1" "testa2" "testb2"])
=>
:clojure.spec.alpha/invalid

seancorfield03:04:54

I'm not sure what you're asking...

Garrett Hopper03:04:24

Is there a way to make the above work while keeping the s/and?

seancorfield03:04:38

I don't understand what you're trying to do, sorry.

seancorfield03:04:44

(that spec makes no sense to me)

Garrett Hopper03:04:56

And not requiring [["testa1" "testb1"] ["testa2" "testb2"]].

Garrett Hopper03:04:13

That's alright. I'm not understanding this very well myself.

seancorfield03:04:51

Take a step back, and explain what is it you're trying to write a spec for -- explain it in words, not code.

Garrett Hopper03:04:52

I want to have pairs of things in a list and an arbitrary predicate that's dependent on both values.

Garrett Hopper03:04:23

I'm attempting to spec out a macro to create proxying proxies.

(defproxy menu
  Object
  [func1 func2])
The spec for [func1 func2] is dependent on what Object is.

Garrett Hopper03:04:55

However, I don't want to have Object and [func1 func2] inside their own wrapper.

seancorfield03:04:56

(s/+ (s/cat :a string? :b string?)) will accept a collection of strings and conform to a collection of maps (each map containing :a and :b).

Garrett Hopper03:04:37

Yeah, that works fine. The issue is when I add in the s/and it then requires a wrapper.

seancorfield03:04:56

So write the spec for the collection of things, then wrap the whole spec in s/and and have it process all the conformed values.

Garrett Hopper03:04:11

I didn't expect that. I thought s/and with a single argument was basically a passthru.

Garrett Hopper03:04:33

Oh, that makes sense. I'll create a predicate for everything instead of for each pair.

seancorfield03:04:03

That predicate would be #(every? pair-predicate %) I think...?

Garrett Hopper03:04:24

Yeah, that makes sense. I just wasn't thinking about it that way.

Garrett Hopper03:04:31

I'm still trying to get into the spec mindset.

seancorfield03:04:42

A key thing to "get" with spec is to not over-specify things: write "just enough" spec for the structure and then tighten the screws with additional predicates.

Garrett Hopper03:04:39

Thanks for the tip

Garrett Hopper03:04:00

It's a stupid example, but it works great.

(s/conform (s/and (s/+ (s/cat :a string?
                              :b string?))
                  (partial every? (fn [{:keys [a b]}] (= a b))))
           ["testa1" "testa1" "testa2" "testa2"])
Thanks

4
emccue07:04:10

This is the first im hearing about Graal

emccue07:04:32

Is this a reliable thing?

emccue07:04:39

Im just in shock a little

schmee07:04:57

it’s legit

schmee07:04:20

there are lots of good talks on youtube if you want to know more, here’s one: https://www.youtube.com/watch?v=mMmOntDWSgw

😮 4
gklijs08:04:14

It’s not production-ready right? Heard of it before looks very interesting.

benzap08:04:12

Are there some good tips and tricks for retaining the collection type when performing operations on a collection?

benzap08:04:42

Really, it's just a problem between (into '() '(1 2 3)) and (into [] [1 2 3])

schmee08:04:50

@gklijs the 1.0.0 release was yesterday, so it’s ready

benzap08:04:59

All they need to do is get graalvm compiling into webassembly, and we'll have reached the singularity

gklijs08:04:27

1.0 not necessarily means production-ready, kafka was production ready long before the 1.0 release.

benzap08:04:33

so if i'm getting this correctly, graalvm is a vm built on top of the JVM?

benzap08:04:00

Wow, graalvm is a pretty crazy achievement

benzap08:04:46

I find it kind of odd that they haven't listed python

schmee08:04:18

the Python implementation is quite new, I don’t think it was around when that slide was made

Aleksander08:04:24

As far as I understand you can run GraalVM on top of Node.js or standalone as well

Aleksander08:04:21

"It can run either standalone or in the context of OpenJDK, Node.js, Oracle Database, or MySQL. "

benzap08:04:51

Yeah, that video @schmee posted goes over all of it, this is blowing my mind

Aleksander08:04:11

Is there a chance for official TruffleClojure?

benzap08:04:32

I'd love to see that

benzap08:04:42

I wonder if graalvm runs on android

benzap08:04:22

could maybe get clojure working on android at significantly lower instantiation times if it can be baked into a native executable

matan08:04:00

do we have O(1) for get/put arrays in clojure?

matan08:04:18

or we can only use Java's arrays for that?

benzap08:04:13

@matan don't take my word on it, but I believe clojure's collections are O(logn)

benzap09:04:08

or most of them are at least, I think the persistentlist is probably O(1) for removal and insertion

matan09:04:16

yeah, I'll use its array functions, such as int-array

matan09:04:27

they wrap around Java's as far as I can see

leonoel09:04:40

clojure arrays are java arrays

matan09:04:56

clojure arrays, meaning int-array and such right?

matan09:04:10

:thumbsup:

leonoel09:04:12

and aget/aset map to standard java array lookup so performance expectations should match

matan09:04:14

many thanks!

leonoel09:04:25

be careful of hinting though, reflection can seriously harm perf

matan09:04:42

right! thanks for reminding me to hint!

elarouss12:04:29

Hi! i'm about to start a personal web project, and i wonder which server should i use, aleph, http-kit or immutant, knowing that it will be (mostly) a real time app?

pesterhazy12:04:47

My advice: most "real time" apps are primarily request/response driven with one component that requires live updates

pesterhazy12:04:38

So optimize for the former, then add a simple component that handles only the minimum, i.e. the push part (SSE or websockets)

pesterhazy12:04:12

There's even a SaaS that does this for you: https://pusher.com/ Great way to simplify your architecture if it fits your app

pesterhazy12:04:31

They use an OSS daemon under the hood, can't find the name ATM

pesterhazy12:04:11

Basically what I'm saying is don't let get distracted by the real-time part or let it infect your project with incidental complexity if you can help it

elarouss12:04:11

@pesterhazy thanks man, you saved me a day of search, i'm not an experienced programmer though, i just have an idea and wanted to see if it's worth building

Alex Miller (Clojure team)12:04:39

There are some differences between primitive and object type hints

ajs12:04:42

ah, so primitive type hints (long, integer, ... maybe string?) are only for fn args, but custom object hints could be more liberally used?

Alex Miller (Clojure team)12:04:03

But you can generally use either of them in many places

ajs12:04:39

in cases where I have locals bound in loops, i'll often do (loop [^Integer x ... appropriate?

ajs12:04:34

the problem is I am working on a data set that is about 10 million integers, so I'm trying to figure out how best to keep it from taking a few minutes to do its thing. The equivalent C++ code is at least 100 times faster for me at the moment.

ajs12:04:57

so tracking down all the places where type hints could be useful

Alex Miller (Clojure team)12:04:45

You really want to avoid boxed numbers, which is particularly challenging in Clojure for ints

ajs12:04:49

part of it also confusion over syntax and how they work, for example if i know the result of a function call is a long, where do I put this? In the function definition itself, in the local I am binding to the result, or both, and in the latter case, would you also ever do something like (let [x ^Long (some-fn-returns-long)... or only in front of the var/local name?

Alex Miller (Clojure team)12:04:37

In general you should put in the place where it has an effect on the most places possible

Alex Miller (Clojure team)12:04:18

So in this case I’d put it on the return type of the function

ajs12:04:36

(defn ^long some-fn [] ...) like so?

ajs12:04:24

and ^long and ^Long are synonymous?

Alex Miller (Clojure team)12:04:26

No, put it before the arg vector

Alex Miller (Clojure team)12:04:50

In that placement you’re type hinting the var

ajs12:04:27

At the repl both seem to have the same effect of enforcing via cast exception that the return is a long

Alex Miller (Clojure team)12:04:45

There is no casting here

ajs12:04:09

thanks for the help, by casting i just meant the exception from this (defn ^long f [] :hi)

chrisblom12:04:29

it there an easy to use clojure library to manipulate git repos available? I’ve used clj-jgit in the past, but found it pretty complicated. I’m looking for something that supports the basic git commands (reset, pull, commit)

val_waeselynck14:04:42

> it there an easy to use clojure library No. Lots of simple ones though </just-kidding>

val_waeselynck14:04:03

Seriously though, maybe JGit? http://www.eclipse.org/jgit/ I haven't used it at all, but for this sort of niche problem I tend to look for Java libs and use interop

qqq13:04:15

with deftype, is there a fundamental limitation of "members of type = members passed to constructor" ?

noisesmith13:04:52

not only that, but the declaration order determines the order the constructor takes them

qqq13:04:32

I was hoping there was some black magicery where we define a specialy named method, which then overrides the default constructor, but I guess that is not supported

vemv13:04:43

@qqq there's such a thing for defrecord (not for deftype though), are you familiar with it?

qqq13:04:45

I've used it a few times; I would not say I understand the details of it.

vemv13:04:08

cljs.user=> (defrecord Foo [a])
cljs.user/Foo
cljs.user=> (map->Foo {:a 2 :b 3})
#cljs.user.Foo{:a 2, :b 3}
cljs.user=> (Foo. 2 )
#cljs.user.Foo{:a 2}

qqq13:04:27

I'm lookinat at https://clojuredocs.org/clojure.core/defrecord is there a way to do custom constructors?

bronsa14:04:43

just write a wrapping function

emccue14:04:06

@benzap I use clojure.algo.generic.fmap

emccue14:04:58

You usually need more than map, but I really like it

emccue14:04:00

the other tools I know about are using (into (empty my-coll) (....some transforrm of my-coll....))

emccue15:04:47

@foobar Is this a "cannot find class" error when you try and import it or a "when I try to use it it cant be resolved in that place"

emccue15:04:57

@qqq My understanding is that (make-x ...) is the best way to handle that

emccue15:04:34

By which I mean just a regular function that returns the record

jmckitrick15:04:45

Has anyone here been part of a Scala shop that transitioned to Clojure, or started using Clojure?

👋 4
dadair15:04:16

We are currently in that transition

the2bears15:04:22

Had the opposite experience - took a role that was for "Clojure", and then once there was told to pull it apart and make Scala micro-services. Not there anymore 🙂

jmckitrick16:04:00

How did you help those who depended on types to get over that hump?

dadair16:04:08

I introduced them to spec and instrument

erwinrooijakkers15:04:42

Is there a way to extend clojure.core’s functionality? For example, have the function range also work on strings? Now: (range "foo") throws >1. Unhandled java.lang.ClassCastException > java.lang.String cannot be cast to java.lang.Number > Numbers.java: 96 clojure.lang.Numbers/isPos > Range.java: 80 clojure.lang.Range/create Is there a way to extend range so that when you call it with a string as first argument it does something different? I guess it would be dangerous, but I am curious.

bronsa15:04:33

technically yes but don’t do that

bronsa15:04:39

we have namespaces for this reason

bronsa15:04:48

just define your own range function and shadow c.c/range

erwinrooijakkers16:04:39

Yes I figured. Is it possible in ClojureScript? Since there are different protocols there?

erwinrooijakkers16:04:49

Disclaimer: I still need some education on protocols.

Bravi15:04:33

hi everyone. I’m trying to do something like this - I have a vector of maps and I’m trying to pick certain values from each map (specifically strings) and concat them afterwards with a white space inbetween

(def users [{:first "John"
             :last "Smith"
             :age 33}
            {:first "Jane"
             :last "Smith"
             :age 22}
            {:first "James"
             :last "Smith"
             :age 2}])

(->> users
        (map (juxt :first :last))
        (map (interpose " " %)))
and I’m stuck there :d basically I want the result to be ["John Smith" "Jane Smith" "James Smith"]

joelsanchez16:04:15

bear in mind, that doing two passes over a seq when you could do one, is not very desirable

Bravi16:04:06

ah damn I was so close haha 😄 yeah, I know but I was just playing around with juxt

Bravi16:04:34

will it actually iterate twice though? will it not create a lazy sequence in that case and iterate once?

joelsanchez16:04:54

look for transducers if you want that optimization

Bravi16:04:14

thanks @joelsanchez. I was missing the transducers piece

Sallide16:04:01

Hi all, has anyone used clojure during typical algorithm interviews? Was wondering if it's a bad choice because space complexity will be hard to analyze

dpsutton16:04:53

"can you do it in place" "no". seems easier to me 🙂

dpsutton16:04:25

but honestly you'll probably run into an issue of your interviewer not knowing clojure

dpsutton16:04:46

unless its a clojure shop, in which case its a great interview language

noisesmith16:04:40

@squarenegative space complexity is still knowable though - yes laziness and chunked allocs change things but they are managable

dpsutton16:04:24

I was thinking persistent data structure made it particularly hard

dpsutton16:04:02

If you assume they are all copies it will be atrocious

noisesmith16:04:35

but they aren't

john17:04:45

I thought an interesting exercise was to use clj-memory-meter while repeatedly updating and conjing a data structure onto itself. While this would break things in other languages, you can create synthetically large structures in clj that are too big to actually realize if you were to try to read the whole thing.

john17:04:54

allowing you to operate incrementally over data domains that essentially don't fit in your memory

emccue17:04:42

@squarenegative I used it in my interviews with intuit and it worked out fine

emccue17:04:29

If we are talking the ratio of interviewer understanding to space on a whiteboard the winner is still probably python

emccue17:04:01

Just be sure to know your audience

dpsutton18:04:18

My friend was asked to explicitly not use it. Maybe ask your interviewer if it's ok beforehand. Takes a bit of a shift if you can't

hmaurer21:04:08

Is there a nice standard function in clojure to generate a sequence from a seed value by, at each point, generating the next value by applying some function on the seed, and either carrying on with a new seed value or ending the sequence

hiredman21:04:10

iterate does stipulate that the function must be free of side effects

hmaurer21:04:45

@hiredman and to “terminate” when I reach some value, I would do a take-while?

hiredman21:04:17

I usually just copy and paste unfold (or at this point just rewrite from memory)

hmaurer21:04:47

thanks @hiredman 🙂 I wanted to write a function to get the digits of a number in a list. Do you think that makes sense:

(defn digits [n]
    (take-while pos? (map #(rem % 10) (iterate #(quot % 10) n))))
?

hmaurer21:04:53

or is there a more elegant way to write it?

dpsutton21:04:21

(digits 10000001) => (1)

dpsutton21:04:28

take-while pos? doesn't work

hmaurer21:04:37

yep there is a bit of a bug with 0s there 😕

dpsutton21:04:39

unless that fits your specific use case

Alex Miller (Clojure team)21:04:25

(defn digits [n] (map #(Long/parseLong (str %)) (str n))) ? :)

Alex Miller (Clojure team)21:04:44

(defn digits [n] (map #(- (int %) 48) (str n))) ;; ascii power

hmaurer21:04:55

@alexmiller haha well, I wanted to try to avoid the conversion to string

hmaurer21:04:58

but that works yes

dpsutton21:04:45

if you rewrite into a loop / recur it should be easy. and then your pos? check makes sense.

hiredman21:04:26

or just swap the order of the rem and the take-whiel

💯 4
jjttjj21:04:51

If I’m making a library that connects to a server and upon establishing a connection receives an api version number, and this version number is used throughout a ton of single threaded boundry transformation multimethods (ie parsing the native representations of various types into clojure maps), but only used in about half of the total transformation multimethods, might this be a good use case for using a dynamic var for the version number and just wrapping the transformation calls in a binding?

dpsutton21:04:21

@hmaurer check the last digit on that. i'm getting (digits 1) is empty list.

hmaurer22:04:06

@dpsutton it works if I include @hiredman’s suggestion I think

hmaurer22:04:14

(defn digits [n] (map #(rem % 10) (take-while pos? (iterate #(quot % 10) n))))

dpsutton22:04:00

ah good call. i had not moved the take while inside

artenator22:04:00

just started getting an odd emacs/CIDER issue today… when i evaluate a cljs buffer, i get an error stating there’s no CLJS repl open (even though there is) When I try to evaluate a CLJ buffer, it loads it into the CLJS repl…. Anyone run into this issue before?

dpsutton22:04:38

@soosool12 there was a bug with a cider-nrepl snapshot released today. try lein -U deps to pull this new version or blow away ~/.m2/repository/cider and then crank it back up and all should be well

dpsutton22:04:07

the problem is that the cljs repl never got correctly created. so you are just left with two clj repls. more in #cider if you want 🙂

artenator22:04:47

@dpsutton ahhhh thank you so much. i had no idea there was a #cider channel. Will post in the correct place next time. Really appreciate the quick reply!

dpsutton22:04:40

no worries. it's not really "wrong" here. #emacs, #clojurescript and #cider all work for this. sorry about the bug and come hang out in #cider!

qqq23:04:07

for a module with one api, but different impls for js/jvm, is it better to have: 1. foo.cljc OR 2. foo.cljs + foo.clj in same directory