Fork me on GitHub
#clojure
<
2018-10-29
>
pesterhazy09:10:29

Writing a Lambda/API Gateway fn in Clojure, I need an adapter that translates requests into Ring request/response format: - locally I can just run Jetty+Ring - routing is done in the Ring handler (e.g. compojure) - on Lambda, I can set up an ANY route with path * that forwards all requests to the Ring adapter There are a few projects on github along those lines like https://github.com/indabamusic/ring-aws-api-gateway-lambda-adapter and https://sideshowcoder.com/2018/05/11/clojure-ring-api-gateway-lambda/ - can anyone recommend a project?

dominicm10:10:02

I think the portkey guys were working on this. I'm not sure about completion.

pesterhazy10:10:06

@dominicm I think portkey is far more ambitious than what I'm looking for (basically a few lines of code, https://github.com/mhjort/ring-apigw-lambda-proxy)

Karol Wรณjcik10:10:44

Does it make sense to use core.typed in 2018?

Dormo11:10:56

Did it ever make sense? :thinking_face:

Dormo11:10:55

I used to be really excited for core.typed, but after writing more Clojure I'm finding that I don't really want static typing.

danielneal11:10:27

I think core.typed can generate specs from tests which is pretty clever. Not really tried it though, just seen it talked about https://github.com/clojure/core.typed#runtime-spec-and-type-inference

zilti11:10:54

There might be use cases for it, but honestly... core.spec does this job really well, even better.

Johnap1912:10:26

๐Ÿ™‚

๐Ÿ‘‹ 4
acron12:10:56

is there a high-order equivalent of or? I'd like to do something like (def invalid-number? (or* zero? neg?)) ... (remove invalid-number? numbers)

tristefigure13:10:09

I wrote https://github.com/TristeFigure/weaving for this purpose. The function you're looking for is called or|. I don't use it much, but it's a great addition when you're writing a DSL. My policy when writing a DSL tends to follow the Data > Function > Macro dogma (https://lispcast.com/data-functions-macros-why/) when it is large enough. But when it is a small/private DSL, I tend to favor functions over data because the obscurity implied by functions underweights the task of implementing basic conditional flow in a data-driven DSL.

acron12:10:10

Ah, some-fn looks like it works in this context

achikin13:10:13

One of my collegues has discovered transducers recently and now he tend to turn every simple map function into a combination of a map transducer and (into []) like this

(into [] (map fn) coll)
;;instead of
(map fn coll)
I think that in our case, when coll has around 10 to 20 values in it, such transducer usage is overkill and harms readability. What do you think? Maybe I'm overseeing something and there are other reasons to do so?

frenata13:10:55

Even when there's only one mapping function?

frenata13:10:10

The case you quote exactly, there's the benefit of putting it into a particular shape ... I might be tempted there but there isn't much difference between (into [] (map fn) coll) and (into [] (map fn coll)) anyway. But I generally only bother when there's a series of transformations.

achikin14:10:15

There was no need to turn it into a []. My collegue is using (into []) because it accepts transducer as an input.

frenata14:10:28

Yeah if the shape isn't needed and there's only one transformation this is overusing the tool for sure.

alexmiller14:10:52

I agree that this is not something you should do everywhere and the seq version can even be faster (with small coll size and one op)

wilkerlucio16:10:27

also there is mapv which is pretty much the same as using (into [] (map ...))

Bravi13:10:54

hello clojurians. where can I see the list of all available protocols?

tristefigure13:10:53

You're lucky, I'm working on a project that exactly does what you want (hope I haven't missed anything extracting this snippet out of it).

๐Ÿ˜ 8
tristefigure13:10:12

Oh and I think sort should be replaced with set and = with clojure.set/subset?.

tristefigure14:10:28

Also replace ns-map with ns-interns otherwise you'll have duplicates in the end result.

tristefigure16:10:18

Since I know both Clojure and Ruby quite well, feel free to share your post so that I can review it. Also you might be interested in some functional combinators I wrote for Ruby. In particular have a look at these experiments that explore how Ruby's scope works. https://github.com/TristeFigure/tissage/blob/master/examples/closures.rb

๐Ÿ‘ 4
valerauko16:10:53

I'd love to take a look and offer insights where applicable

๐Ÿ‘ 4
danm16:10:23

What library would people use these days for easily-configurable XML parsing and editing?

danm16:10:44

I know zippers allow editing, but xpath gives a really easy way to have runtime-configurable statements like "Find all of element X where it has a child element Y with attribute Z having value A". I want to then be able to say "and delete the node (X)"

valerauko16:10:58

I use clojure.data.xml for xml parsing / output, though I'm not doing any real heavy lifting.

danm16:10:13

Yeah, that's what we're using at the moment. But it really doesn't lend itself to runtime configuration of paths

danm16:10:10

With xpath you can do stuff like /elementA[/elementB/@attr = ("val1" "val2", "val3")] to find the relevant nodes

danm16:10:38

Something that would then let me just remove the found nodes would be great

danm16:10:40

With clojure.data.xml as far as I have found I have to manually build functions to do that sort of thing and it's not easy to make it configurable.

narendraj917:10:28

Do we have syntax for having arguments to a function as an additional vector?

(defn some-fn [a b c :as input-vector] ...)
where input-vector will be [a b c] inside function body.

narendraj917:10:14

For example, this works

(defn some-fn [& [a b c :as input-vector]] (println input-vector))

narendraj917:10:02

but allows more than 3 arguments.

andy.fingerhut17:10:22

Not that I can think of, built in. You can make one inside the function if you want, of course.

frenata17:10:47

in other words, you want to enforce that the vector is exactly (or no more than?) length 3?

narendraj917:10:17

I had a function definition

(defn ->some-map
  ([a b c]
   ...)
  ([input-vector]
   (apply ->some-map input-vector)))
I was thinking if I can get rid of the multi arity using some built-in destructing.

narendraj917:10:24

I need the input-vector inside the 3-arity function for logging.

andy.fingerhut17:10:58

You mean a function that takes either 3 separate arguments, or 1 that is a vector, without defining it as a multi-arity function, and with automatic checking that number of args is 1 or 3? No, I really don't think that is built in.

andy.fingerhut17:10:49

And some people might suggest you be cautious about introducing such "punning" in args your functions accept, lest you confuse yourself or library clients later, but I won't go far in that direction.

๐Ÿ‘ 4
narendraj917:10:58

I don't want to get rid of the arity, I just need the vector inside the 3-arity function to log it without constructing one myself with the three arguments. Nevermind, it's not that important. It will make it trickier to read the definition.

hiredman17:10:50

there is no vector, so you will have to construct it if you want it

andy.fingerhut17:10:47

If your function took exactly 1 arg, and it was a vector with at least 3 elements, you could do destructuring for that 1 arg, but I don't think that will enforce exactly 3 elements in the vector, only at least 3.

๐Ÿ‘ 4
hiredman17:10:25

it won't enforce at least 3 either, I don't think

hiredman17:10:37

user=> ((fn [[a b c]] [a b c]) [1])
[1 nil nil]
user=> 

frenata17:10:54

& [a b c] will not enforce the length of the vector, no

narendraj917:10:03

user> (defn some-fn [& [a b c :as input-seq]]
                     (println input-seq))
#'user/some-fn
user> (some-fn 1 2 3 4)
(1 2 3 4)
nil
user> 

hiredman17:10:12

(isn't a vector either)

shaun-mahood20:10:35

@seancorfield It looks like the generated API docs are out of date for clojure.core.cache - is that something you can update or is it part of some larger Clojure thing? Took me a while to figure out what was going on (the API docs don't have through-cache and I was going a little crazy trying to figure out where it came from ๐Ÿ™‚ )

seancorfield20:10:41

@shaun-mahood Technically it's a build infrastructure thing that's broken -- @alexmiller?

octahedrion20:10:43

how to use :exclusions in deps.edn ?

ghadi20:10:08

@octo221: like so

com.cognitect/transit-clj {:mvn/version "0.8.300" :exclusions [org.javassist/javassist]}

alexmiller21:10:07

@shaun-mahood @seancorfield yes, itโ€™s somewhat manual right now. But just pushed update http://clojure.github.io/core.cache/

jaawerth21:10:12

What's a good word for a function that, like juxt, accepts multiple functions and returns a single function that accepts a vector (or sequence, I guess) and invokes each input function on its correspondent element in the sequence/vector? I find this can come up a lot in data pipelines. unoptimized version basically being (fn [& funcs] (partial map (fn [f x] (f x)) funcs))

jaawerth21:10:36

this is a common enough usecase I wouldn't be surprised if I missed it already existing somewhere in core, too

jaawerth21:10:40

it's sort of an anti-juxt, lol

enforser21:10:41

maybe like map-each

enforser21:10:42

maybe a slightly nicer way to define it: (partial partial map (comp eval list))

ghadi21:10:03

no don't eval

ghadi21:10:22

that also won't work unless it's a macro or if the input is raw forms

ghadi21:10:14

(eval involves the compiler and classloading, and will be very surprising)

jaawerth21:10:39

yeah it's fun to be able to (partial partial map) but eval is evil ๐Ÿ˜›

enforser21:10:42

ah, I didn't know that! I'll look up more info on when (not) to use eval

jaawerth21:10:56

I did consider a macro but it fails the "if you can do it without a macro, don't use a macro" test

seancorfield21:10:17

The first rule of eval club is: never use eval ๐Ÿ™‚

ghadi21:10:34

no macro necessary... you were close with the original code, but I think you should reexamine the semantics you want

jaawerth21:10:49

oh? what's wrong with the original?

ghadi21:10:00

usually my input is maps, not sequences

ghadi21:10:20

but I want to augment the map with extra data that comes from applying a series of functions

hiredman21:10:23

I've found something similar to https://aphyr.github.io/tesser/tesser.core.html#var-facet useful a few times (but I've never actually used tesser)

ghadi21:10:29

{:firstname "Ghadi" :lastname "Shayban"}

;;;  :full-name (fn [m] (str (:firstname m) " " (:lastname m)))
;;;  .... more keys + functions

jaawerth21:10:34

this is primarily for scenarios wherein you have functions that operate on one argument and you need to use them in a composition or transducer pipeline that needs to operate on tuples

jaawerth21:10:44

I'm sure there's a haskellish word for it

hiredman21:10:51

facet is similar to the vector thing, but for maps

jaawerth21:10:32

thanks. come to think of it I've seen this kind of thing called "project" before for map-like structures

ghadi21:10:34

but I think use-cases differ enough that there isn't a one-size-fits-all.

jaawerth21:10:23

I'm surprised other people don't run into the usecase for mine more often - any time you're using pipelines that can only pass a single container and you're forced to instead give a vector or fixed sequence, basically

jaawerth21:10:10

channels, transducer pipelines, composed core.reducer pipelines, etc

jaawerth21:10:00

not that it's usually hard to just wrap the pre-exisitng one-arg function(s) manually, I just find it can hurt readability

hiredman21:10:06

reducers/tranducers is exactly what I've used facet for

jaawerth21:10:35

yeah looking at tesser now, thanks

jaawerth21:10:51

and yeah it's the same thing, just for positional stuff rather than keys

jaawerth21:10:59

@hiredman ha, tesser actually probably would have improved the performance of the task I was doing that had this come up - though I did end up parallelizing it a bit with clojure.core.reducers/folder and some core.async stuff