Fork me on GitHub
#clojure
<
2017-12-21
>
synthomat00:12:21

i also have a small question using the thread-last macro, can I make an exception for one of the elements and insert the result as first argument?

synthomat00:12:56

I tried to wrap it in a #(myfunc % params) but it doesn’t seem to work; neither does a fn 😞

synthomat00:12:15

I ended up writing an extra function outside of the thread

synthomat00:12:38

hm, I guess I misunderstood thread macros; they take the functions as partials and appends an extra argument before actually calling the function? using other macros as functions might break the thread macros…

justinlee00:12:08

maybe use the as-> macro?

synthomat00:12:21

nah, looks weird 🙂

synthomat00:12:44

but is my assumption correct? (if someone understands my writing…)

phronmophobic00:12:00

it doesn’t create partials

phronmophobic00:12:05

it rewrites the code

phronmophobic00:12:25

so you can use the anonymous functions, but it often requires extra parens

phronmophobic00:12:09

(-> [1 2 3 4]
    (->> (map #(+ 10 %))
         (map str)
         (clojure.string/join ","))
    (clojure.string/replace #"," "."))

phronmophobic00:12:34

pardon the terrible example

synthomat00:12:40

hm, I didn’t mean “real” partials… but I think I understand now why it didn’t work

phronmophobic00:12:47

you can “embed” thread last in a thread first

phronmophobic00:12:54

but not the other way around

phronmophobic00:12:18

you can also use the anonymous functions with extra parens

phronmophobic00:12:40

(->> [1 2 3 4]
    (map #(+ 10 %))
    (map str)
    (clojure.string/join ",")
    (#(clojure.string/replace % #"," ".")))

phronmophobic00:12:58

you can also use the as-> macro

synthomat00:12:40

woah, the extra parentheses did the trick 🙂 thanks

phronmophobic00:12:52

i’ve also seen folks write

(-> [1 2 3 4]
    (->> (map #(+ 10 %)))
    (->> (map str))
    (->> (clojure.string/join ","))
    (clojure.string/replace #"," "."))

synthomat00:12:08

I think I finally started understanding clojure today 🙂

synthomat00:12:39

(->> (apply concat (vals js))
     (reduce reducer {})
     (#(json/encode %1 {:pretty true}))
     (spit "extract.json")))

phronmophobic00:12:39

i’m still not sure which form I prefer

noisesmith00:12:25

another variant

(-> [1 2 3 4]
    (->> (map #(+ 10 %))
         (map str)
         (clojure.string/join ","))
    (clojure.string/replace #"," "."))

noisesmith00:12:39

showing that it’s not partial application

=> (-> [a 1 b 41] (let (+ a b)))
42

justinlee00:12:01

it’d be neat if there was an as-> and as->> that defaulted to thread-first or thread-last if no $ was found

rymndhng00:12:49

I'm really tripped up on this java interop issue: I want it to call remove(int index) -- what would I have to do to typehint this correctly? This is the class: https://hc.apache.org/httpcomponents-client-ga/httpclient/apidocs/org/apache/http/impl/client/RedirectLocations.html I tried to create a function

(defn do-it [^org.apache.http.impl.client.RedirectLocations redirect-locations ^Integer index]
  (.remove redirect-locations index)) 

noisesmith00:12:32

for some methods you might need to call int to cast the arg, recall that in clojure 1 is not an Integer, it’s a Long

rymndhng00:12:42

right, so i'd wrap index with (int index) -- I tried that, still doesn't work

noisesmith00:12:51

what error are you getting?

synthomat00:12:03

@noisesmith just tried to understand your example from above… it wouldn’t work with (->> X (-> Y) Z) right?

noisesmith00:12:31

@synthomat correct - all the other arrow macros nest inside ->, but -> can’t nest inside ->>

noisesmith00:12:16

it has to do with the mechanics of the code rewrite (the silly example with the let is to show that it isn’t smart at all - it’s just moving tokens around in lists)

rymndhng00:12:20

@noisesmith I'm not getting an error, but it's returning a boolean false which is coming from the other method signature. boolean remove(URI uri)

noisesmith00:12:57

@rymndhng ahh - what if you hint ^int instead of ^Integer?

noisesmith00:12:31

(I bet I have a project with this dep, I’ll see if I can replicate in a repl)

rymndhng00:12:37

how do i typehint with ^int, i get Unmatched delimiter: )

hiredman00:12:40

don't do that, do (.remove redirect-locations (int index))

hiredman00:12:02

(without the extra i)

noisesmith00:12:16

kingfisher.core=> (defn rm [^RedirectLocations r ^long idx] (.remove r idx))
#'kingfisher.core/rm
kingfisher.core=> (rm red 0)
#object[java.net.URI 0x2a3988c0 ""]

rymndhng00:12:02

interesting that you typehinted a long

hiredman00:12:10

(set! *warn-on-reflection* true) will tell you if the compiler is emitting reflection

noisesmith00:12:23

int primitives are not supported by the clojure compiler

noisesmith00:12:31

so I made it a long, and it worked

hiredman00:12:46

or just call int

noisesmith00:12:59

@hiredman it was still calling the wrong method when I called int

noisesmith00:12:00

kingfisher.core=> (defn rm2 [r idx] (.remove r (int idx)))
#'kingfisher.core/rm2
kingfisher.core=> (.add red 0 (java.net.URI. ""))
nil
kingfisher.core=> (rm2 red 0)
false

noisesmith00:12:23

boolean is what the Object overload returns if it gets hit

hiredman00:12:53

you aren't hinting r

rymndhng00:12:56

i tried using (int x) instead of the typehint and it worked as well

hiredman00:12:59

you need to do both

rymndhng00:12:05

it appeared typehinting r was the thing i missed

hiredman00:12:56

turning on reflection warnings will make it clear when you have eliminated the reflection or not

hiredman00:12:57

the long hint also causes the function to implement the primitive invoke stuff(if I recall), which is orthogonal to compiling an invoke of the right method

rymndhng00:12:16

thank you gents -- i need to practice up my interop & reflection fu

noisesmith00:12:36

something that’s helpful sometimes is a leiningen plugin called no.disassemble - it can expose what your function compiles down to as readable mnemonics for the byte code https://github.com/gtrak/no.disassemble

PB01:12:44

Upgrading to clj 1.9. Anyone else getting these error messages?

WARNING: boolean? already refers to: #'clojure.core/boolean? in namespace: clojure.tools.analyzer.utils, being replaced by: #'clojure.tools.analyzer.utils/boolean?
WARNING: boolean? already refers to: #'clojure.core/boolean? in namespace: clojure.tools.analyzer, being replaced by: #'clojure.tools.analyzer.utils/boolean?
WARNING: bounded-count already refers to: #'clojure.core/bounded-count in namespace: clojure.core.async, being replaced by: #'clojure.core.async/bounded-count
?

hiredman01:12:37

have you upgrade core.async recently?

hiredman01:12:43

are you using require :all or use?

hiredman01:12:41

my guess would be you have an older version of core.async that doesn't exclude bounded-count from clojure.core

PB01:12:32

@hiredman I have upgraded core.async, currently running on [org.clojure/core.async "0.3.465"]

PB01:12:44

This is the ns def in the file in question:

(:require [clojure.test :refer :all]
            [amazonica.core :refer [defcredential]]
            ;; our stuff
            [com.stuartsierra.component :as component]
            [clojure.core.async :as async :refer [go go-loop >! <! timeout alts! alts!!]])

PB01:12:30

It is having issues on my call to go-loop but I'm not quite so sure why

PB01:12:37

It appears I just needed to run lein clean 😕

PB02:12:42

Appreciate the time and thoguht @hiredman

qqq02:12:00

@bronsa: yeah, I can definitely do a bit more clojure source reading. How do you find the source? checking out clojure + grep, or the github interface, or repl/source, or ... ?

synthomat02:12:45

open your favourite IDE, type a method, click on “go to source” or similar

synthomat02:12:33

or use REPL with (source SOME-COMMAND), but it’s not really useful to “browse”

qqq07:12:28

@tbaldridge: re parsing / ometa : I figured out what I was looking for -- parsec

fabrao08:12:29

Hello all, I'm developing a reporting generator but in Java/Clojure I do not have the right library for the charting session. The charting library is in javascript, so, is there possible to generate the charts from javascript/html and use it in Clojure as svg or image without having server/browser generating it?

fmind09:12:45

@fabrao you have the option of using nodejs or rhino to run JS without a browser

qqq09:12:46

how cheap/expensive is (fn [] ...) is it as cheap as a function call, or is creating anonyous functions at runtime realy expensive ?

leonoel09:12:44

it is as cheap as an object creation can be

qqq09:12:45

naively it seems for a (fn [] ...) there is some compilation / byte code generation to be done, which might make it expensive

qqq09:12:01

does clojure somehow do all this pre-emptively and cache it (despite not having the environment until runtime)

leonoel09:12:45

each function generates a class at compile time

leonoel09:12:43

then it is lazily loaded by the classloader as with java

qqq10:12:15

this is a drastic oversimplification, so you're saying: 1. at compile time, each (fn [...] ...) has a class generated for it 2. at runtime, when to exec the code, the corresponding code is passsed the env as an argument, creating a "clojure function object" 3. this "function object" can then be used just like any other clojure functions, and passed arguments to make it work ?

qqq10:12:10

thanks; this explains so much!

leonoel10:12:48

I learned a lot about the compiler by decompiling my clojure code

qqq10:12:27

I tried that once, but the decompiler lib crashed the JVM, and I never tried it again.

dominicm11:12:03

Where is the linux installer versioned? (If at all)

dominicm11:12:26

(For the clj command line tool)

qqq12:12:11

why is there no pop-n! and peek-n (for pop! peek associated with vector)

mbjarland13:12:10

@dominicm if by versioned we mean versioning the install script itself, seems that it already is at https://clojure.org/guides/getting_started, but maybe I'm missing your point

dominicm13:12:08

I mean is it in a version controlled repo

mbjarland13:12:12

@dominicm it seems (at least from this cursory check) to live in the https://github.com/clojure/brew-install repo under src/main/resources/linux-install.sh and be versioned using the script under , which on the last line says:

aws s3 cp --only-show-errors "target/classes/linux-install.sh" "$S3_BUCKET/install/linux-install-$version.sh"

mbjarland13:12:26

where on the 1.9.0 branch in that git repo, the maven pom.xml says <version>1.9.0.275</version> and looking at git history we can see that the version was changed to 275 from 273 on dec 8 and 273 is what we see on the site

dominicm13:12:20

Great find 👍 Thanks. Looks like the two are versioned together.

qqq13:12:36

is there a shorter way to write:

(fn [stack & lst]
              (reduce #(%2 %1) stack lst))

Miķelis Vindavs13:12:21

not 100% sure what it’s supposed to do, but ((apply comp lst) stack)?

Miķelis Vindavs13:12:03

or ((apply comp (reverse lst)) stack) I suppose

mbjarland13:12:53

@qqq what is that function supposed to do? if the incoming stack is in fact a list that we are just treating like a stack and all you are doing is adding all the elements from one list to another (the stack) then you could as well just return lst or potentially (reverse lst). But I get the feeling we are missing your point

qqq13:12:58

oh sorry, let me rewrite that as

qqq13:12:20

(fn [obj & list-of-fns]
              (reduce #(%2 %1) obj list-of-fns))

qqq13:12:45

so there is an object, there is a list of functions, we want to apply it one by one, so (magic obj f1 f2 f3 f4 f5) --> (f5 (f4 (f3 (f2 (f1 obj)))))

qqq13:12:57

I'm writing a simple forth interpreter

qqq13:12:06

the object here = stack, and the list-of-fns = words

Miķelis Vindavs13:12:55

wrt your question earlier https://clojurians.slack.com/archives/C03S1KBA2/p1513859891000026 it’s highly inefficient since it involves copying

Miķelis Vindavs13:12:57

if possible, try to reframe the problem so that you can use first/last for vectors or first for lists

Miķelis Vindavs13:12:10

often, a hash-map is also a better choice

manutter5113:12:37

@qqq Oh now you’re making me jealous, I’ve always wanted to write my own Forth interpreter.

cvic13:12:34

Forth in Lisp. And Lisp in Forth.

cvic14:12:24

> Forth: the original bare-metal REPL

manutter5114:12:12

I should never have sold my C64.

tbaldridge16:12:31

@manutter51 I'm sure there's cycle accurate C64 emulator out there now 😄

manutter5116:12:10

I’m trying to pretend I don’t know that. 😉

mdrago102616:12:32

does anyone here have any experience using clj-http with cookies on an HTTP/POST? I’m trying to convert a request over from using [http.async.client “1.2.0”] to clj-http

rymndhng17:12:46

@mdrago1026 are you experiencing issues? what version of clj-http are you using (hopefully latest version: 3.7.0)?

mdrago102617:12:26

@rymndhng I just got it to work. I am on 3.7.0. I was trying to pass the cookies map the previous authentication request returned into the :cookies value of the POST map. For whatever reason it wasn’t worker. Passing the raw cookie string to the :headers map worked though

mdrago102617:12:47

I was under the impression you could pass the :cookies map around

mdrago102617:12:16

was just doing an auth, getting that cookies map and sending it in the subsequent POST

schmee18:12:34

@mdrago1026 you should be able to pass the :cookies map directly, I have some code around that does that

kulminaator19:12:07

i need a bit of advice , i'm pretty sure someone has solved my issue already but i seem have trouble finding it. I need a persistent map that is stored on disk and doesn't require me to read it all into memory to read it.

kulminaator19:12:30

sure i could do all sorts of h2 or hsqldb sort of trickery but i really would rather not 😞

kulminaator19:12:17

the reason why i don't want to read all into memory at once is that it just won't fit, amount of data is way bigger than the ram that i have available

luskwater19:12:33

Maybe use Datomic Free version? (Or the free Datomic Pro?)

kulminaator19:12:24

datomic seems pretty complex for my needs 🙂

noisesmith19:12:04

isn’t what you need just a database?

kulminaator19:12:52

yes but the definition of a database is a rather wide one

manutter5119:12:11

maybe just sqlite or something? Sounds like that might be adequate, depending on just how big we’re talking here

noisesmith19:12:16

OK just saying what you describe so far is something any database worthy of the name does

kulminaator19:12:25

i manage apps that run on postgresql clusters of hundreds of gigabytes every day at work , and yeah sure that's all fine and i know how they work ... but my needs here are way different

luskwater19:12:43

Well…. that depends on the keys @kulminaator is using: could be objects, vectors, etc.

noisesmith19:12:06

OK no database (or nearly none) supports all the types clojure allows in hash map keys

noisesmith19:12:38

if you have a decade to spare you could make a new database sure

kulminaator19:12:44

i usually despise orms and simplifications but this time it is exactly what i'm looking for, just a memory optimized storage for hash maps , which in turn have just lists of strings as values and strings as keys

kulminaator19:12:57

something in the berkeleydb or mapdb territory

New To Clojure19:12:08

Why database? Most likely only one map type is needed.

New To Clojure19:12:52

mapdb seems to be the way to go

noisesmith19:12:07

@ghsgd2 because most people want insertion to be reliable and persistent and failures to be handled in a sane manner and multiple clients to be able to access it without breaking everything etc. and before you know it either you have something that doesn’t work at all, or a database

noisesmith19:12:17

I’m not talking about query models or relations or anything here - you don’t need those to be a db

gklijs19:12:17

MVStore is easy to use, but I moved to Redis, since I needed access from multiple jvm's. Also easy, but needs a separate process.

kulminaator19:12:49

but wasn't the case with redis that whatever you store there, even if backed on disk, needs to fit in ram ?

kulminaator19:12:21

h2 is a strong candidate on my checklist so far though

gklijs19:12:01

Yes, that's true, so for this case it doesn't work

kulminaator19:12:00

thanks for the suggestions, i will break my thumbs a little bit on testing approaches out

wiseman19:12:42

@manutter51 @qqq this is my favorite lisp/forth story: http://www.flownet.com/gat/jpl-lisp.html (starting with “Also in 1993 I used MCL to help generate a code patch for the Gallileo magnetometer…“)

kwladyka20:12:02

(try
  (throw
    (ex-info "foo" {:bar "barrr"}))
  (catch Exception e
    (ex-data e)))
vs
(try
  (throw
    (ex-info "foo" {:bar "barrr"} {:baz "baaz"}))
  (catch Exception e
    (ex-data e)))
Second example return nil. First example is clojure.lang.ExceptionInfo while second is java.lang.ClassCastException. How do you read Expection in consistent way to get always ([msg map cause] from ex-info? On the end i need it to create fingerprint for sentry, which is unique data to identify group of errors.
(when (or error-message (force msg_))
                                                         (->> [?ns-str error-message (force msg_)]
                                                              (remove #(= "" %))
                                                              (remove nil?)))
So i want add here additional cause to make smaller group of errors to easier debug issues. So on the end i want call:
(throw
          (ex-info "service X API" {:error-info "bla bla" {:cause {:timeout :foo}}))
^ or maybe last param could be a vector [:timeout :foo] or just in some cases
(throw
(ex-info "service X API" {:error-info "bla bla"))
In logs i want make from that right fingerprint for sentry to group this errors. How to get ex-data and cause from ex-info. When third parameter cause is present in ex-info it returns different instance and it doesn’t work so simple.

kwladyka20:12:17

wooo… too long. sorry, but wanted well describe it

kwladyka20:12:52

PS [?ns-str error-message (force msg_)] this part is from timbre envents

noisesmith20:12:46

(ins)user=> (ex-info "" {} {})
ClassCastException clojure.lang.PersistentArrayMap cannot be cast to java.lang.Throwable  clojure.core/ex-info (core.clj:4739)
the ClassCastException is because you used ex-info wrong, and you get the thrown ClassCastException instead of the other one you were catching

noisesmith20:12:55

the third arg if present needs to be a throwable

noisesmith20:12:44

it’s not that ex-info is returning a different type, it’s throwing instead of returning

kwladyka20:12:52

oh…. thanks.

noisesmith20:12:25

the design is that cause if present would be another exception (the one you caught originally in theory)

kwladyka20:12:58

I throw this exceptions myself, so…. hmm maybe I shouldn’t use cause in that case.

kwladyka20:12:29

Do you know some good practice how can i make fingerprint to group exceptions?

kwladyka20:12:14

It would be grate to don’t have timeout issue from third part service etc. in the same group like others important errors

kwladyka20:12:16

For now only one solution what i see is change "service X API" in ex-info but i don’t like it to much

(throw
          (ex-info "service X API" error-info))

kwladyka20:12:10

(when sentry-dsn
(l/debug "sentry-dsn: " sentry-dsn)
(sentry/init! sentry-dsn)

(timbre/merge-config!
{:appenders
{:sentry
{:enabled? true
:async? true
:min-level :debug
:rate-limit nil
:output-fn :inherit
:fn (fn [{:keys [level ?err msg_ ?ns-str context]}]
(let [error-message (some-> ?err (.getLocalizedMessage))]
(sentry/send-event (merge sentry-base
{:level (get timbre->sentry-levels level)
:fingerprint (when (or error-message (force msg_))
(->> [?ns-str error-message (force msg_)]
(remove #(= "" %))
(remove nil?)))
:logger ?ns-str
:extra context
:message (not-empty (force msg_))
:throwable ?err}))))}}}))
^ here is the point how I use timbre events

kwladyka20:12:20

ach it looks so ugly in thread

kwladyka20:12:02

hmm alternatively I can use :causes from ex-info map always as some kind of agreement.

qqq20:12:49

is there any plan to make (> \b \a) to ever return true ?

noisesmith20:12:13

@qqq by redefining clojure.core/> or shadowing it

noisesmith20:12:29

oh sorry I misread - no, no plan for that

andy.fingerhut20:12:32

@qqq (clojure.core/compare \b \a) returns 1. That might be useful to you.

noisesmith20:12:09

@qqq the clojure numeric operators will not be made generic / extensible beyond working on Number

qqq20:12:09

I currently have new functions c> and c< for char

qqq20:12:46

Here's a Joy DSL I'm working on. Feedback/criticism welcome:

(defn fnj-raw [args body] `(fn [ss#] (let [[ss# ~args] (vsr ss# ~(count args))]
                                        (vrc ss# (do ~@body))))) 
  (defmacro fnj [args & body] (fnjp-raw args body))
  (def joy  (fn [stack & lst] (reduce #(%2 %1) stack lst)))
  (def joy1 #(first (apply joy [%1] %2))) 
  (def jw   (fn [& lst] #(apply joy % lst)))

  (def jdup   (fnj [x] [x x])) 
  (def j+     (fnj [x y] [(+ x y)]))
  (def j-     (fnj [x y] [(- x y)])) 
  (def j*     (fnj [x y] [(* x y)]))

  (def jp     (fn [x] (fnj [] [x])))
  (def jcct   (ffnj [x y] [(concat x y)]))
  (def js2    (jw jdup j*))

  (def jfilter (fnj [lst ws] [(filter #(joy1 % ws) lst)])) 
  (def jmap    (fnj [lst ws] [(map #(joy1 % ws) lst)]))

  (def jc>    (fnj [x y] [(c> x y)]))

  (joy ["John Smith"] (jp [(jp \Z) jc>]) jfilter) 
  
  #_ (def ji     (fn [lst] #(apply joy % lst)))
  #_ (joy [1 2] (jp (ji [j+ (jp 20) j* (jp 10) (jp 4) j-])) ji)

  (joy [2] js2)

  (joy [] (jp 2) (jp 3) j+ jdup j*)

  (joy [] (jp [1 2 3 4]) (jp [jdup j*]) jmap)

noisesmith21:12:53

you don’t even need nippy for string/string right?

qqq22:12:52

is there a clojure data structure that gives amortized O(1) pop/peek, and O(1) concat ?

seancorfield22:12:23

@qqq If you don't need it to be eager, concat is already going to be O(1), right? 🙂

seancorfield22:12:19

So a list would be O(1) pop, peek, and (lazy) concat but you trade off O(n) on other operations...

seancorfield22:12:26

If what you're concating is always small, a vector is going to be reasonable: O(1) for pop, peek (off the end) and (into vec1 vec2) will be O(n) for the size of vec2... and you still have O(1) access to other elements...

seancorfield22:12:47

(I think -- happy for someone to confirm / deny my thinking there!)

andy.fingerhut22:12:28

@qqq RRB vectors gives amortized O(1) pop/peek, and O(log n) concat: https://github.com/clojure/core.rrb-vector

andy.fingerhut22:12:01

or maybe it is O((log n)^2) concat -- been a while since I looked at the details. Anyway, significantly less than O(n)

qqq22:12:08

@seancorfield @andy.fingerhut: theXY problem is that I am implementing an 'instruction stack' most of the time, it's just pop and peek, but occasionally, I need to push a buch of ops to the front of it

noisesmith22:12:47

sounds like you want clojure.lang.PersistentQueue/EMPTY

qqq22:12:55

no, queue are fifo, I need lifo

noisesmith22:12:00

conj to the front peek/pop from back

noisesmith22:12:26

@qqq you know that conj takes multiple args and that you can use into as well right?

qqq22:12:33

yes, but I believe that becomes liner time, not O(1)

justinlee22:12:25

doesn’t a doubly linked list do that for you?

qqq22:12:25

doubly linked lists really aren't functional

qqq22:12:39

ot "merge" the two lists, you have to modify the prev/next pointersx

jgh22:12:25

is there a way to make jdbc dump the sql statements it’s making? I have a sql query that is working through psql but it doesnt return anything through jdbc, and I don’t get any errors either…

noisesmith22:12:25

yeah, you can’t do the sharing clojure would normally do with lists

justinlee23:12:47

what about those zipper things that I refused to learn about when i was trying to learn haskell

noisesmith23:12:44

> to make a doubly-linked list, you need to construct it all at once, and if you ever want to change any part of it, you either need to use a Zipper or just make a complete copy of it every time https://stackoverflow.com/questions/10386616/how-to-implement-doubly-linked-lists

noisesmith23:12:56

@qqq did anyone mention finger trees yet?

jgh23:12:24

why do sql query examples not use the goddamn results

seancorfield23:12:57

@jgh Ask in #sql if you want to avoid the noise of this channel...

qqq23:12:55

@noisesmith fingertrees look interesting

qqq23:12:39

I just had an epiphany while implementing Joy in Clojure. Stack based langauges = basicaly programming iwth de bruijn indices instead of variable names.

andy.fingerhut23:12:42

If you are worried about constant factors in run time, you might want to do some profiling of finger trees vs. other data structures like plain old Clojure vectors and/or RRB vectors. I haven't done it myself, but recall that finger trees have constant factors of run time significantly higher than the others. Not O() bad things, but something that might affect what you want to use anyway.