Fork me on GitHub
#clojure
<
2017-12-18
>
qqq01:12:48

`(#(reverse (apply vector %&)) :a :b :c)` is there a way to rewrite the function? (the part before the :a 😛 :c)

Chris O’Donnell01:12:05

(comp reverse vector)

qqq01:12:30

actually, I think ikt's just #(reverse %&) 🙂

qqq02:12:01

(defmacro def-alias [lst] 
    `(do ~(for [[k v] lst] `(def ~k ~v))))

  (macroexpand-1 
   '(def-alias [[rev reverse] [ki keep-indexed] [pi persistent!] [ti transient] [gi get-in]]))
(comment
 (do
 ((def rev reverse)
  (def ki keep-indexed)
  (def pi persistent!)
  (def ti transient)
  (def gi get-in))))


what am I doing wrong in this macro?

qqq02:12:38

ah, it should be ~@(for instead of ~(for

fmind07:12:45

Did you guys checked https://github.com/EntilZha/PyFunctional ? I'm wondering if I could create a similar project with clojurescript.

cmal07:12:23

Hi, I use

(defn gen-handler
  [k]
  (eval
   `(defn ^::blocking ~(symbol (str (name k) "-handler"))
      [state#]
      (try
        (handlers/do-handler state#)
        initial-state
        (finally (run *agent*))))))
to define function at runtime, but it appears the new xxx-handler function was defined at clojure.core namespace, not the namespace which gen-handler was called or defined. How to define a function at runtime at the current namespace? Thanks!

noisesmith17:12:19

Because *ns* is a dynamic var, the “current namespace” is not the one in which the function was defined, it’s the one in which the code is running. If the defn needs to happen in a specific namespace, use in-ns to make sure that’s the context. You can also use intern which explicitly takes a namespace as an argument.

noisesmith17:12:24

Clojure 1.9.0
(ins)user=> (create-ns 'foo.bar)
#object[clojure.lang.Namespace 0x5443d039 "foo.bar"]
(ins)user=> foo.bar/baz
CompilerException java.lang.RuntimeException: No such var: foo.bar/baz, compiling:(NO_SOURCE_PATH:0:0)
(ins)user=> (intern 'foo.bar 'baz "hello")
#'foo.bar/baz
(ins)user=> foo.bar/baz
"hello"

qqq07:12:56

(def □ 20 )
□
(comment
 20)


so it clearly works however, according to https://clojure.org/reference/reader#_symbols is this guaranteed to work? in particular, it states:
Symbols begin with a non-numeric character and can contain alphanumeric characters and *, +, !, -, _, ', and ? (other characters may be allowed eventually).
and I do not know how unicode is defined wrt to alphanumeric

fmind08:12:42

@cmal have you considered using macro that this use case ?

cmal08:12:30

@fmind I am not sure, does macro different with function in this use case?

cmal08:12:02

at every thread the agent runs in, I use (gen-handler k) to generate a handler to do a specific job.

cmal08:12:21

this handler is generated using the keyword k so I can later using keyword k to get the function's name and call this function.

fmind08:12:24

do you have a specific reason to define top-level function with defn ? It might be more appropriate to create anonymous function with lambda

fmind08:12:45

like in this case, where I define two handler functions

(defn pipe "Create a parallel pipeline."
  [xf in out err]
  (let [n ncpu
        close? true
        to (async/chan n)
        from (-> in line-seq async/to-chan)
        ln-handler (fn [x] (writeln out x))
        ex-handler (fn [x] (writeln err x))]
    (async/go-loop []
      (when-let [ln (async/<! to)] (ln-handler ln) (recur)))
(async/pipeline-blocking n to xf from close? ex-handler)))

andy.fingerhut09:12:35

@qqq Not sure what you mean by "is it guaranteed to work"? Do you mean, will it ever change in a future version of Clojure? It is unlikely that it will change, as the Clojure core team likes to maintain backwards compatibility, but I don't think they or anyone else can make you some kind of binding promise about it.

andy.fingerhut09:12:08

I believe the Eclipse Public License is pretty much a guarantee that you can use all versions of Clojure released under that as long as you want to, but that may not be what you are asking about.

qqq11:12:33

@andy.fingerhut: re "unicode in clojure", my current understanding is: 1. unicode var names works in 1.9.0 2. unicode var names is NOT promised to work according to clojure docs 3. I'm curious whether I can rely on unicode var names working in the future

tvalerio13:12:04

Is there a way in Pedestal to automatically reject http requests that is not accepted by the application depending on `Content-type´? I tried the above code but I think I didn’t undestand what pedestal does

(ns job-queue.service
  (:require [io.pedestal.http :as http]
            [io.pedestal.http.route.definition :refer [defroutes]]
            [io.pedestal.http.body-params :as body-params]
            [ring.util.response :as ring-resp]
            [io.pedestal.http.content-negotiation :as conneg]
            [io.pedestal.http.route :as route]
            [job-queue.api.agent-api :refer [add-agent]]
            [job-queue.api.job-api :refer [get-jobs]]))

(def supported-types ["application/json"])

(def content-neg-intc (conneg/negotiate-content supported-types))

(defn home-page
  [request]
  (ring-resp/response {:message "pong"}))

(defroutes routes
  [[["/" {:get home-page}
     ^:interceptors [(body-params/body-params) http/json-body]

     ;;agent api
     ["/v1/agents" ^:interceptors [content-neg-intc] {:post add-agent}]

(def service {:env :prod
              ::http/routes routes
              ::http/resource-path "/public"
              ::http/type :jetty
              ::http/port 8080
              ::http/container-options {:h2c? true
                                        :h2? false
                                        :ssl? false}})

tvalerio13:12:26

and my add-agent always return HTTP 200`

(defn get-jobs
  [r]
  {:status  200
   :headers {"content-type" "application/json;charset=utf-8"}})

tvalerio13:12:34

When I send a request with Content-type text/html the response is HTTP 200 too

luchini16:12:37

Anyone know of any library wrapping an external queue (rabbitmq, Kafka, etc) as clojure.async channels?

tbaldridge16:12:10

@luchini I’ve done it several times, but getting the semantics right can be tricky

tbaldridge16:12:33

Esp once alt! gets involved

donaldball16:12:47

Be wary of claiming to have processed a message that you have merely dumped into a channel

tbaldridge16:12:58

Kafka is probably the easiest since it’s immutable

luchini16:12:53

@tbaldridge any open source library that already does it or did you implement it yourself?

miro16:12:45

@luchini funny just opened the slack now as i was just doing some coding on this. Spent few hrs today reading through the code, but in terms of alt i still cant figure out how the handler fn callback on take! is NOT called (or is kinda rolled back) for the channels that do not end up first (in the race condition). I have done this kinda implementation few times in past, but alt i always coded myself because of this. I originally thought the mutex between channels is shared, but it does not seem so; the alt-flag locking also does not seem to do the job.... @tbaldridge if there is no available library but you still could point me to the right namespace and line of code that addresses this that would be very much appreciated ... i should be (edit: hopefully) able to figure out the rest....

luchini17:12:09

@miro one way or another it would be great to have this as a library

luchini17:12:25

The potentials are huge

tbaldridge17:12:09

@miro I would recommend thinking about the relationship between the queue and the channels. What do you want to happen if a message is 3 channels deep into your app and the service dies?

tbaldridge17:12:30

What I recommend is instead passing an ack funtion with the message, and then the last thread In your channel chain calls that to tell the queue that the message ha been processed

tbaldridge17:12:14

In short, it’s a mistake to ack the message when it goes onto a channel. Queues are durable, channels are not.

miro17:12:22

@tbaldridge yes, acking i do once the message is processed, keep that as a function of a message or a session. But what i struggle with is how to leverage existing implementation of alt!!.. I always implemented that myself (usually multiple threads polling/waiting on queues with a use of locking and nacking messages that arrived second) because i couldnt figure out how the take! callback would have to look like so as it would work with the core async alt implementation. So my question is what method in clojure.core.async.impl.protocols.Handler is in charge of the "rollback" in case the alt's take! from a channel finishes second?

tbaldridge17:12:38

That’s the problem I think you can avoid. Just keep messages as data and use the default implementations of alt!

tbaldridge17:12:05

Don’t try to do ack as part of an alt!

tbaldridge17:12:51

Not only is it hard to implement, I’m not sure it’s possible to do correctly with a mutable queue.

luchini18:12:31

Thanks guys. This is amazingly useful

lxsameer17:12:29

hey folks, I want to create a series of videos in order to tech clojure in my local language to those who are interested.

lxsameer17:12:43

I'm a bit dizzy about the TOC of the course.

lxsameer17:12:18

do you think that the lisp concepts are important in the beginning ?

lxsameer17:12:15

or do you know a good presentation or a course in English which i get inspiration from ?

admay19:12:54

@lxsameer https://www.braveclojure.com/clojure-for-the-brave-and-true/ Might want to check out #beginners and ask around there too

jgh19:12:15

datomic vs postgres for a simple-ish ecommerce site, what are your opinions? I like the temporal nature of datomic, in that if I update facts older transactions remain valid. Vs changing things in a regular rdbms where it can also change prior transactions if not done right. Also the datalog integration with clojure is really nice. But $5000/yr/system ;(

jgh19:12:04

sql through clojure doesn’t seem great, but maybe I’m missing a critical library that helps out a bit (Is HugSQL any good?)

admay19:12:06

@jgh HugSQL is great! I’ve been incorporating it into my projects more often lately and I love it! I’m a fan of free so I usually go Postgres but that’s just me

andrea.crotti19:12:19

is using sut as name of the system under test when creating test namespaces a bad practice?

andrea.crotti19:12:51

that's what cider does by default when creating a new test file, but could not really see anywhere if it's a good practice or not

bostonaholic19:12:29

I do not prefer it, I end up changing it to whatever the pattern is for that ns in the rest of the program

bostonaholic19:12:59

e.g. myapp.thing :as sut -> myapp.thing :as thing

bostonaholic19:12:38

so I can more easily grep for usages of thing/foo and other reasons

andrea.crotti19:12:58

yeah I also prefer not to use it for that reason

plins19:12:04

@jgh checkout also honeySQL !

jgh19:12:09

cool, thanks for the suggestion. I’ll be doing most stuff in stored procs (if I go with postgres) but this looks like a great option for executing those.

jgh19:12:16

er well i guess postgres is a bit different from the last time i did a sql database lol, i see they dont really do stored procs. So nevermind that then!

plins19:12:24

hello everyone, im trying to generate a fat jar of a main application (its not a webserver it just starts some jobs and then dies), but i keep getting errors lein with-profile dev uberjar produces: java.lang.IllegalArgumentException: env variable ‘:db-host’ is not set, compiling:(cfg.clj:17:1) I have a profiles.clj populated with the right env variables, it does work while working inside the repl

jgh19:12:05

ah great….seems my google-fu is weak today

qqq20:12:32

;; foo.cljc
(ns foo (:require [clojure.spec.alpha :as s]))
(defmacro tm [& lst] `(s/def ~@lst))

;; bar.cljc
(ns bar (:require [foo])) ;; notice, we don't alias spec.alpha
(macroexpand-1 '(foo/tm 1 2 3)) ==> (clojure.spec.alpha/def 1 2 3)
so it appears the s/def is being expanded at DEF MACRO time, not at USE MACRO time. I find this counter intuitive. Can someone explain the machanics by which this is happening ? [ I was expecintg an error saying there is no such namespace in ns bar ]

bfabry20:12:33

macros are expanded at macroexpansion time

bfabry20:12:53

if you want to expand them at runtime then you need eval

luskwater20:12:56

In order to avoid capturing and re-using some symbol in bar, ordinary symbols are expanded before you leave foo. You would need

(defmacro tm2 [& lst] `(~'s/def ~@lst))
to quote the use of s/def to carry that over and pick up whatever that meant in the environment you are expanding in (here, bar)

qqq20:12:49

@bfabry: is 'macroexpansion' time (1) when macro is defined or (2) when macro is used ?

bfabry20:12:59

oh, except the time of expansion is not your issue here. like lukswater said you're just expecting ` to work differently to how it does

qqq20:12:30

@luskwater: I see the

`(~'s/def
trick now, thanks!

bfabry20:12:35

` syntax-quotes a bunch of stuff given the context of its definition

luskwater20:12:51

Somewhere there’s an extensive essay on quoting in Clojure macros

qqq20:12:31

I'm sure there is, but it's the type of dry stuff that I don't expect to understand until I run into issues of "I expect FOO, but I got BAR"

shaun-mahood22:12:08

@dnolen: Great Codemesh talk - I'm loving all of your recent Datomic outreach efforts.

petterik22:12:07

Here's a link to the talk for anyone interested: https://www.youtube.com/watch?v=nbMMywfBXic

mrg22:12:21

Can somebody explain this to me please?

mrg22:12:42

both on cljs (lumo) and the JVM

hiredman22:12:37

it looks like clojurescript is confusing reduce and transduce somewhere

phronmophobic22:12:45

the first example has a one item collection and the second has two items

phronmophobic22:12:07

the first example will never use the function to combine elements

phronmophobic22:12:12

because there is only one element

phronmophobic22:12:23

whereas the second example will

hiredman22:12:39

(yeah, I misread that)

bronsa22:12:43

@mrg that behavior is explicit in reduce's docstring

mrg12:12:17

You are right, thank you. It did totally catch me by surprise though.

bronsa22:12:54

If coll has only 1 item, it is returned and f is not called.

qqq22:12:55

I understand that boot/lein uses JVM. I understand that Macro system uses JVM. Right now, in Clojure dev, I use cider to talk to a JVM repl -- is there anyway to make it practical to talk to a node.js repl instead ?

dpsutton23:12:26

i think you want inf-clojure

qqq23:12:43

No, I'm not after an emacs mode.

seancorfield00:12:41

CIDER is basically nREPL middleware so it's JVM only. Can you explain what you think you want to connect to a Node.js REPL?

tbaldridge00:12:53

Socket repls are completely possible.

tbaldridge00:12:38

lumo and planck both support socket repls. As does the CLR.

qqq03:12:30

@U04V70XH6: my current setup is client side = cljs; server side = clj via jvm ;; I am considering changing server side to cljs via nodejs

qqq03:12:44

but it's not clear to me how to get a 'cljs repl on nodejs' on the server side

qqq03:12:03

@tbaldridge: are those meant as dev environments, or a way to write shell scripts in cljs ?

seancorfield04:12:16

@qqq I think you'll be in relatively uncharted territory. Have you asked folks in #clojurescript ?

seancorfield04:12:55

For Expectations, which -- notionally -- supports ClojureScript as well as Clojure, the cljs tests are run using a cljs REPL but it's bootstrapped from a Clojure REPL (on the JVM).

tbaldridge04:12:38

Both, planck runs on JS core (self hosted) so you're a bit limited, but lumo runs on Node.JS and can use node modules

tbaldridge04:12:51

not really sure what you mean by "used as a dev env" though

tbaldridge04:12:42

a REPL is a dev environment

dpsutton04:12:17

and you can use planck and lumo with inf-clojure so emacs can work with them similar to CIDER but without the huge jvm deps

seancorfield05:12:50

Good to know! Just installed npm on my Windows 10 WSL Ubuntu bash and then installed Lumo via npm and, sure enough, I can start a Socket Server REPL and connect to it from telnet or similar... Not sure whether that helps @qqq (and I see Lumo advertises its cljs compilation as experimental) but it's impressive.

seancorfield06:12:13

And it looks like Lumo's cljs compilation is a lot more solid now (just reading the mid-September blog post about it).