Fork me on GitHub
#clojure
<
2017-03-24
>
dragoncube00:03:55

@hlship any plans to support cljs for client part of lacinia?

pyr07:03:25

hi @martinklepsch, sorry i'm a bit behind but should have time to look into the issue this weekend.

jumar07:03:45

Would you consider the following to be a reasonable (i.e. readable, performant, and idiomatic) implementation of "longest common prefix" for two strings?

(defn- longest-common-prefix [a b]
  (->> (map vector a b)
       (take-while  (fn [[char-a char-b]] (= char-a char-b)))
       count))

martinklepsch07:03:37

@pyr no worries, I think it’s probably not even related to unilog but I don’t know enough about this stuff to really tell...

ordnungswidrig08:03:16

@jumar I think it depends on how similar the strings are in general. I could imagine that using a bi-sectioning algorithm may be faster.

jumar08:03:24

yeah, that's true. Let's say we have no idea how the strings look like and that performance is slightly important, but not the most important factor. Or we can just ignore it for a while and focus on "readable" and "idiomatic" 🙂.

ordnungswidrig08:03:55

You implementation is fine, you can optimize by replacing the anonymous fn with =:

ordnungswidrig08:03:57

(->> ["abcdef" "abdd"] (map vector) (take-while =) count)

rauh09:03:16

@ordnungswidrig I don't think that works.

mpenet09:03:57

(map vector [a b]) is not the same as (map vector a b)

ordnungswidrig09:03:14

@rauh you’re right (->> ["abcdef" "abcefgh"] (apply map vector) (take-while (partial apply =)) count) it is. I was fooled by getting the correct result, 2.

cddr10:03:32

How do you combine multiple lein profiles in combination with the "+" operator that makes them add to the default profile?

borkdude12:03:38

Is there a function that selects keys according to an example map, like: (f {:a {:b 1 :c 2} :d 2} {:a {:b identity}}) ;;=> {:a {:b 1}}

borkdude12:03:53

Maybe Specter can do this? (cc @nathanmarz )

lsenjov12:03:00

There's select-keys, although that's only one level deep

ihabunek12:03:40

I'm having trouble using java.util.ArrayList in Clojure, specifically the remove(int index) method which is supposed to remove the item at given index. It always returns false (meaning item not removed). There is also a remove(Object o) method which removes the given object from the list, and this method works as expected. Here's the code to reproduce:

(import '[java.util ArrayList])
(def foo (new ArrayList [\a \b \c \d]))
(.remove foo \a)        ; true
(.remove foo (int 1))   ; false
I presume the integer is not passed as a primitive, but the docs say: > Coercion ops int, float, etc. produce primitives when consumer can take primitive > (let [foo (int bar)] …) is the correct way to get a primitive local. Do not use ^Integer etc. https://clojure.org/reference/java_interop#primitives I would appreciate if anyone knows what's up here.

borkdude12:03:17

@ihabunek (.remove ^ArrayList foo 1)

ihabunek12:03:22

@borkdude thanks, that works

ihabunek12:03:45

how come (.remove foo \a) works?

lsenjov12:03:23

As a thought, perhaps turn on *warn-on-reflection*, which may have thrown up a warning when you tried to run compile it

ihabunek12:03:37

@lsenjov yes, that threw a warning > call to method remove can't be resolved (target class is unknown)

ihabunek12:03:53

interesting

ihabunek12:03:17

i don't have much experience with java interop, didn't know warn-on-reflection was a thing

lsenjov12:03:19

Aye, the type hinting borkdude said resolved it

lsenjov12:03:25

I didn't for a long time either

lsenjov12:03:42

If you're using lein, you can set it in your project.clj

ihabunek12:03:53

already on it

lsenjov12:03:05

:global-vars {*warn-on-reflection* true}

borkdude12:03:17

@ihabunek Without the type hint, it probably sees (.remove foo (int 1))) as a call to remove the object (int 1)

borkdude12:03:28

@ihabunek which it hasn’t, so it returns false

borkdude12:03:52

is my guess

ihabunek12:03:55

i started with (.remove foo 1), which doesn't work, then tried using (int 1)because of what the docs say

ihabunek12:03:35

btw, is there a more idiomatic way of doing this: i have a large list (3M+ entries) and i need to (drop-nth) repeatedly. Using vectors, this is slow, because i need to create a new vector each time i drop an element.

borkdude12:03:27

@ihabunek You could use a transient

borkdude12:03:20

@ihabunek Although I’m not 100% sure what your problem looks like. Transients are mutable counterparts which are only to be used within a function for optimizations

nathanmarz12:03:39

@borkdude I've thought about having maps implicitly work that way by translating themselves into multi-path + keypath

nathanmarz12:03:30

never had a need for it though, but easy enough to implement yourself by extending ImplicitNav to maps

borkdude12:03:55

@nathanmarz I’d like to use it for a light weight graphql like query to trim down a JSON response

nathanmarz12:03:49

also there's no performance cost to using ImplicitNav since it is invoked only on the first time through that code and then cached

nathanmarz12:03:29

should only be a few lines of code, if you need help jump into #specter

nathanmarz12:03:49

also it will naturally work for both querying and transformation

borkdude12:03:16

I’m going to look at multi-path and keypath first, thanks!

tbaldridge12:03:57

@borkdude "only within a function" isn't exactly correct. They aren't thread-safe and so you have to do thread management on your own. That's about the extent of it.

tbaldridge12:03:35

but you can use them in stuff like stateful transducers where several functions and function bodies may modify the same transient

gklijs13:03:05

Just as I thought I’d seen all mutable types already. I used volatile as mutable inside a function, but would using transients be more performant? It’s mainly used for building/comparing sets in memory, which seems exactly where transients are useful for.

tbaldridge13:03:30

@gklijs so whenever you modify a collection, (set, vector, map, etc.) you get back a new copy of the collection. This is relatively fast, but Transients let you say: "I'm just going to throw away each result since I'm building a collection and I'm only interested in the final result". So transients allow you to look up and add new values, but that's about it, since they are mutable.

tbaldridge13:03:38

But transients also support O(1) conversion to and from persistent collections. So think of (into [] ...), this is a perfect use-case for transients as you can make the [] into a transient, add all the items, then make it persistent again.

tbaldridge13:03:08

So I wouldn't say you should use them all the time, but if you want to build a collection and do it very quickly, transients are a good place to start.

Alex Miller (Clojure team)13:03:09

if your use case is bulk loading a collection, you should probably use transients

gklijs13:03:35

I have a game-state, which I transform into a deftype object, and there are several collection in the deftype object, that are update for each ‘step’ to predict the next state. All I really need from the fuction is the next best move. So none of the intermediate collection really need to be persistant. Can you also do functions like remove on transients?

gklijs14:03:49

Looks like there is no remove for a transient, but I could do a reduce with pop to get the same result.

newres15:03:36

Hi, I got a question about locally installing project with leiningen. I tried to look up on what the standard way of doing this is, but when I do lein install although the dependency does get placed into the default local repo (~/.m2) a new project that wants to import it can not find it. So how am I supposed to do this properly?

weavejester15:03:34

lein install should just work

weavejester15:03:38

Maybe you have a typo?

newres15:03:14

under "~/.m2/repository/"i get the directory structure projectname/projectname/0.1.0 so I tried [projectname "0.1.0"] but lein deps gives the error

hiredman15:03:45

what error?

hiredman15:03:03

are all of projectname's dependencies available either in your .m2/ or from some maven repo lein can pull from?

newres16:03:02

the error says it could not find artifact in either central or in clojars

hiredman16:03:41

which artifact? the one you installed in your m2? a different one?

newres16:03:52

the newly installed one

newres16:03:29

i basically did a lein install on it, swtiched to the other, added it to the project.clj and ran lein deps on it

hiredman16:03:30

how do you know it is the newly installed one? is it the same coordinates (group id, artifact id, version) ?

newres16:03:06

project is called foo so the error says can not find artifact foo:foo:jar:0.1.0

newres16:03:36

maybe the naming is off somehow?

newres16:03:25

aaaah well got it, glanced over the fact that the version was named 0.1.0-snapshot, whooops

newres16:03:36

well thanks for the help in any case !

newres16:03:18

was confused by the fact that the repo showed a 0.1.0 in the directory listing.

cddr16:03:55

Bumping this in-case there's some lein experts around now that weren't here before: https://clojurians.slack.com/archives/C03S1KBA2/p1490351252897485

cddr16:03:24

i.e. I'd like to do something like lein with-profile +foo,lib-v1:foo,lib-v2 test but I get Profiles in with-profile must either all be qualified, or none qualified

bja16:03:26

can you just include default?

bja16:03:42

lein with-profile default,foo,lib-v1:foo,lib-v2 test

mbcev17:03:36

Is anyone familiar with http://github.com/Gonzih/cljs-electron ?? Long story short I want to use it to build an app but I'm a confused in regards to where my Clojure (aka desktop code) would go and how it would communicate with the ClojureScript/Electron UI code?

mattsfrey17:03:00

i'm not terribly familiar with cljs-electron but very familiar with electron itself

mattsfrey17:03:10

and it uses node so i dont think you'd be using clojure anywhere really

mbcev17:03:30

@mattsfrey so I'm probably using the wrong tool for the job. What I'd like to do is have some clojure code that does some networking stuff and I thought it would be cool to use Electron as a nice front-end for that app. But perhaps my thinking of Electron and CLJS as a "View" for a Clojure "Controller" in a MVC type mindset is misguided. Yes?

mattsfrey17:03:21

you can have your backend server on the jvm and make rest calls to it from an electron frontend

mattsfrey17:03:59

if you want to launch it like an application you'd need to have electron fire up a jvm and run your server jar etc though

mbcev17:03:38

If I were to write the app in a more "traditional" (for me) way I would use Netty for the networking and JavaFX for the UI and it would all be one JAR. But if I wanted to do it the way you're describing the way I should approach it is put together the Aleph Clojure stuff and have it communicate to a separate running instance of Electron right?

mattsfrey17:03:13

yeah basically you'd have electron launch your jar file for the server in a process call

mattsfrey17:03:23

and then your front end could make rest calls to it

mbcev17:03:50

Hmm okay. So cljs-electron uses foreman I guess and it starts up electron then figwheel so if I added an additional call to lein run and wrote my app the way I would expect, then what I need to do is do "typical" server/client comm between the electron and my "server" app right?

noisesmith17:03:30

lein is a dev tool, don’t make an actual app depend on lein being present at runtime

mbcev17:03:45

Hmm, yeah I think you're right. I would be better off with CLJ + some JavaFX to properly bundle it rather than figuring out how I'd properly bundle the electron+clj app. Thanks @noisesmith

bja17:03:44

@mbcev For what it's worth, you could develop your entire app on top of node written in cljs. I think that's what the cljs-electron template is for. Probably better discussed in #clojurescript

mbcev17:03:44

@bja I'll definitely explore more now that I have a better understanding of what Electron is. That was my bad. What I'll probably end up doing is using Clojure to build what I need for right now and then as an exploratory exercise try to re-build it later with Electron and ClojureScript. I'm far less familiar with web related technologies so I think that's why I got tripped up with this.

mbcev17:03:53

Building it with cljs-electron would require me to learn more about Electron and Node/NPM and any and all other associated libs/tools/etc whereas if I stay in the JVM I have less new cognitive overhead for myself.

hlship18:03:15

@dragoncube r.e. cljs & Lacinia: this is not on our radar, it is something that a group with a more client-side focus can take on. Part of the point of GraphQL is a clean separation and contract between client and server. Further discussion on #graphql please.

josh.freckleton19:03:28

I have a SQL table that needs to be grouped according to any combination of ~10 columns. Am I correct that these are my best options, or can you see others? * YeSQL and do the grouping in memory (in clojure) * HugSQL and I can do the grouping in the db now using snippets

tanzoniteblack19:03:17

You should be able to do the grouping in the DB using either YeSQL or HugSQL?

tanzoniteblack19:03:11

What are you trying to group on?

josh.freckleton19:03:22

if i used raw sql (or YeSQL), theres a combinatorial explosion of possible fns I would write oh, and each table can be up to 10-100M rows

josh.freckleton19:03:43

and I'm grouping on some enums, and ids

tanzoniteblack19:03:33

When doing grouping in SQL, it's almost always better to do it in the SQL, as it prevents you from having to send all of the rows down the wire.

tanzoniteblack19:03:53

What makes it a "combinatorial explosion" of fns? Do you have some complicated logic about when to choose which id?

josh.freckleton19:03:24

it's a reporting dashboard, and the client can decide what columns to group by

josh.freckleton19:03:46

so, actually it's prob not combinatorial, but exponential (right?)

tanzoniteblack19:03:27

Doing it in YeSQL would, admittedly, be rather complicated to do without some rather dangerous string splicing. But it does sound like something that HugSQL's identifier lists solves?

seancorfield19:03:39

Have you looked at HoneySQL for composable queries?

tanzoniteblack19:03:52

@seancorfield has a good suggestion. https://github.com/jkk/honeysql will allow you to compose sql queries with native clojure data structures. So you can do what HugSQL is doing with identifier lists in code.

tanzoniteblack19:03:01

You might also consider checking out http://www.metabase.com/ (open source and written in clojure + js/react) for creating flexible dashboards like it sounds like you're trying to do. I use that regularly for that purpose at my job, much easier than spending my time handling the UI and backend side of that when it's already mostly solved by an off the shelf tool. Coincidentally, they use honeysql in their code for composing queries

josh.freckleton19:03:05

@seancorfield thanks, I hadn't considered honeysql for this, so I'll check that out too!

josh.freckleton19:03:20

@U236LQYB0 also considering HugSQL, thanks for weighing in on it 🙂

Aron19:03:33

noob with js background here. what is an idiomatic way in clojure to represent a function with optional static properties attached to it?

josh.freckleton19:03:53

do you mean like a closure?

josh.freckleton19:03:31

(def myfn (let [x 123] (fn [y z] (+ x y z))))

josh.freckleton19:03:09

(defn myfn [x] (fn [y z] (+ x y z))

josh.freckleton19:03:37

so myfn closes over the internal fn which will thence forth have an x

josh.freckleton19:03:03

ie ((my-fn 1) 2 3) ; => 6

josh.freckleton19:03:00

depending on what you're doing, you could also achieve something similar with partial

Aron19:03:25

not really.

Aron20:03:25

it's static, because it does not uses this, it's not a class or some stuff. but functions are objects so you can give them properties, in fact they already have properties like .name and .length

noisesmith20:03:36

there is no way to do this idiomatically in clojure, the closest you can get is metadata

adambrosio20:03:07

why do you want static (function) properties on a function?

noisesmith20:03:16

ashnur yes they are objects, but they don’t support arbitrary data added on

Aron20:03:02

well, if the main thing is a function, it's easy to just use it everywhere, and the attached stuff that is very secondary is used much less, but the two are tightly coupled

Aron20:03:18

@noisesmith in javascript, they do

noisesmith20:03:22

we avoid coupling data and code

noisesmith20:03:30

ashnur congratulations to javascript

josh.freckleton20:03:04

agreed, I haven'y (yet?) seen a use case for what you're asking for, which would lead me to say theres prob a more idiomatic alternative

Aron20:03:22

@noisesmith you are being unhelpful. this wasn't about how js is or isn't, and I already knew that you avoid that coupling, that's why i am asking

noisesmith20:03:27

as I said, this is possible with metadata

noisesmith20:03:30

kingfisher.core=> (def foo (with-meta (fn [x] (+ x 42)) {:a "secret"}))
#'kingfisher.core/foo
kingfisher.core=> (meta foo)
{:a "secret”}

adambrosio20:03:30

unless you are trying to pass the first function and then access the second from that, it's quite easy to just additionally use/refer to that second function

noisesmith20:03:40

but we avoid coupling data and code

Aron20:03:53

@U0CSAHDV0 well, i assume the situation of having to pass around multiple functions together appears quite often in clojure, but i am still waiting for some pointers 🙂

noisesmith20:03:22

ashnur you ignored my first answer (use metadata) hopefully you’ll notice my working example

noisesmith20:03:30

it’s also not idiomatic

Aron20:03:17

@noisesmith i ignored because i know it's not idiomatic, and I sense that the clojure community has better solutions for this specific problems.

noisesmith20:03:35

the solution being don’t tie data to your functions

adambrosio20:03:39

you could bundle the functions in a map {:A (fn [] …) :b (fn [] …)} and then you can access both, one, or none as needed

noisesmith20:03:50

I mean, I guess we can get into bigger picture design and show what we do instead...

adambrosio20:03:53

instead of hiding them in one’s metadata

Aron20:03:05

@noisesmith you continue to be unhelpful, i would appreciate if you would let others answer first, thanks 🙂

adambrosio20:03:31

well but again, what is your use case here…

Aron20:03:03

i want to represent views (takes a db instance, gives back a vnode that represents a html structure)

Aron20:03:12

these views have attached queries to them

Aron20:03:44

basically, i want to know what data each view needs, query for them and give it to them

adambrosio20:03:24

what little i understand of that, it sounds like you would return some datastructure that has a :render method, and a :query method

adambrosio20:03:08

eg: {:render (fn [data] [:div {:class …} …]) :query (fn [db] (query db ..data..)}

Aron20:03:29

not sure what exactly is meant by method in clojure land. in js and java land method is something bound to a this. i am not fond of those kinds of methods

adambrosio20:03:46

sorry overloaded terms, just a function

noisesmith20:03:09

and the idiomatic alternative to a hash-map full of functions is to use defprotocol to define a protocol, and reify that protocol, or define a record implementing the protocol

Aron20:03:29

@noisesmith now you are helpful, thanks 😉

Aron20:03:41

i will explore both suggestions

noisesmith20:03:45

adambros please don’t use the terms method and function interchangibly, they have distinct meanings in clojure and we can use both

Aron20:03:06

@noisesmith what is method in clojure?

noisesmith20:03:59

you have an object, and you call a method on it - eg. as we mentioned functions are objects, (.invoke f arg arg2 arg3) uses the low level interface from clojure.lang.IFn to call the function (just an example, don’t do this in your code)

noisesmith20:03:32

for example (.getTime (java.util.Date.)) returns a number - ms since epoch

Aron20:03:35

yeah, not going to, so methods are the same thing, for java and in case of cljs: js interops

Aron20:03:42

if i understand correctly

noisesmith20:03:11

right - methods belong to objects, and are not first class - you can pass the object as an arg, but not the method - it has no independent existence

noisesmith20:03:26

which is why we invented functions - which are objects with an invoke method

noisesmith20:03:51

(hope that helps)

Aron20:03:21

very strange, but yeah, helpful. thanks again 🙂

noisesmith20:03:05

IFn only needs to exist in java clojure, in js functions already exist and behave close enough to the way we like - you can think of clojure functions as providing for java something close to js functions

qqq22:03:48

did datomic punt the difficulty of persistence / acid by using other dbs as the backend

hiredman22:03:10

#datomic may be a better place for datomic questions

hiredman22:03:02

(I would say "no" to the original question)

hiredman22:03:03

my understanding is that what datomic requires of storage is a key value store and some kind of compare and set operation for keys. you could argue that A and D come from the storage's compare and set and durability of values for keys, but C and I are the result of the database following clojure's epochal time model.

hiredman22:03:21

riak is maybe the most extreme example of a non-acid datomic backend, but even dynamodb(the original backend as far as I know) doesn't provide the guarantees of acid

hiredman22:03:54

the postgres backend may be the only backend that has acid guarantees out of the box

pawandubey23:03:51

I am trying to implement a Producer-consumer type system with core.async using chans and go-loops. Basically building a web-spider. Two channels - one which stores the URLs encountered till now and another which stores the content from the crawled URLs - are used. I am writing and reading from them inside independent go-loops.

pawandubey23:03:15

But when I execute it, an instance of clojure.core.async.impl.channels.ManyToManyChannel is returned.

bradford23:03:16

Hey fam. I'm a bit confused as to why I can't get any concurrency from my core.async code. I basically have a buffer of URLs that I'm feeding to n webcrawlers. Every time there's a new URL, a new crawler service is started. But I'm only getting 1 crawler at a time. Also, my print statement doesn't print. Any ideas?

(def in-chan (async/chan 2))

(defn start-async-consumers
  "Start num-consumers threads that will consume work
  from the in-chan and put the results into the out-chan."
  [num-consumers  chrome save proxyhost proxyport proxypass driver geo]
  (dotimes [n num-consumers]
    (async/thread
      (doall (print (str "New thread" n))
        (while true
          (let [obj (async/<!! in-chan)]
            (.run (core.ServiceDriver. (core.CrawlService. chrome save proxyhost proxyport proxypass driver geo) obj ""))))))))

(defn run [concurrency driver chrome save proxyhost proxyport proxypass geo addy]
  (do
    (start-async-consumers concurrency chrome save proxyhost (Integer. proxyport) proxypass driver geo)
    (while true
      (async/>!! in-chan (core.CrawlQueue/consumeAndReplace addy)))))

pawandubey23:03:55

What are the chances

bradford23:03:21

I just cut like 200 lines of Java to these 15 lines. Lolz.

pawandubey23:03:41

Clojure is fabulous. But I have not been able to grok the async and lazy bits completely yet. And they are burning me out completely on this problem.

pawandubey23:03:12

My crawler code is here, in case anybody is feeling charitable enough to go through it: https://github.com/pawandubey/crawljer/blob/master/src/crawljer/core.clj

seancorfield23:03:42

@bradford Your doall wraps two expressions… I think that’s why your print doesn’t.

seancorfield23:03:34

doall‘s docstring says it takes a coll or n and a coll (but doesn’t explain the n). You’re not passing it a collection tho’...

bradford23:03:13

@seancorfield Ah, thanks. Removing that does not seem to fix the concurrency issue (I wasn't expecting it to)

seancorfield23:03:59

You also don’t need the do in your run function — function bodies can have multiple forms already.

seancorfield23:03:28

What does (core.CrawlQueue/consumeAndReplace addy) do? Will it produce a new value each time it is called?

bradford23:03:44

Yes, it's a blocking call to a queue on AWS

seancorfield23:03:56

I tried your example with a somewhat cut down example (that put random integers into the channel in run and pulled them out and printed them in start-…) and ran it with five consumers and it looked like I was getting all five consumer threads running, taking turns processing the values.

seancorfield23:03:15

If you can’t figure it out, maybe ask in #core-async where you should find folks who use core.async more heavily.

bradford23:03:48

Cool, I'll poke at it some more. .run after that let is blocking, but that should be OK because it's in a thread. Hrmm.