clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
2021-01-22T00:13:38.033200Z

As in, using TCO? Or using no calls at all?

2021-01-22T00:14:19.033400Z

If you mean using no method/function calls at all, the only thing I can think of is the one I mentioned earlier -- implement your own stack and loop while pushing/popping elements of that stack at appropriate times.

2021-01-22T00:24:53.033600Z

I mean without using recursion

2021-01-22T00:25:50.033800Z

And also without using a stack, since the example doesn't need one

2021-01-22T00:26:42.034Z

I guess it would just be a for loop where you mutate the collection being looped over as you loop over it

2021-01-22T01:04:45.034400Z

That example definitely needs a stack that has a depth proportional to the depth of the directory structure of the file system, unless I completely misunderstand the code example.

2021-01-22T01:09:43.034600Z

Or, I guess in the proposed Clojure implementation, the use of an explicit stack was avoided by just keeping one big collection of all files and directories not "visited" yet.

2021-01-22T01:10:04.034800Z

The total memory storage required is the same as if it had been done with a stack of parameter values.

2021-01-22T01:11:45.035Z

In my experience, most places where mutual recursion shows up naturally in code, without forcing it, the maximum call depth is "small", as in the case where the Java code above has a maximum call depth limited by the maximum depth of the file system directory structure.

2021-01-22T01:12:19.035200Z

So TCO is not really needed.

2021-01-22T06:41:40.036Z

https://twitter.com/cgrand/status/1350063059864346624 👀 thoughts?

😎 3
solf 2021-01-22T08:33:33.036500Z

It seems awesome, but there's too few info to really comment on it

baptiste-from-paris 2021-01-22T08:45:45.036700Z

we are working on it, we’ll make a tweet ~1 a week to keep you update

2021-01-22T10:31:35.036900Z

Cool 🙂 This seems next in the line of joker-lang. But please give a cool name 😎

cgrand 2021-01-22T19:18:21.073Z

Unless forbidden to, we’ll go for a boring name like ClojureDart.

👍 1
2021-01-22T22:14:55.114200Z

As I understand, this is compiled to Dart correct? Not an interpreter?

phronmophobic 2021-01-22T22:33:20.114400Z

yea, I think I read a tweet that it produces Dart source code

2021-01-23T00:01:50.129600Z

Oh cool, so it compiles to Dart source code, interesting

2021-01-23T00:04:40.129900Z

Wonder how that will play with REPLs and other dynamic use like "eval" and support for Vars

cgrand 2021-01-23T13:10:37.144Z

It depends. When you run in dev mode, you are in the dart vm and you can redef and eval. The compiler can only run in this mode. When you run your cljd code as a native executable you can’t eval or redef.

👍 1
2021-01-23T23:57:21.236900Z

That seems good then, similar to native Clojure with GraalVM it would seem.

xceno 2021-01-22T18:30:52.047300Z

Is there a way to pretty print transients in the repl, so I see the actual content and not just the type name?

2021-01-22T18:34:47.049100Z

@rob703 I'm realizing that the reason I don't have an answer to this is that I've always taken transients as a hack (14% or so speed increase), so as soon as I need to debug something I stop using them

2021-01-22T18:34:59.049400Z

someone else might have a better answer

xceno 2021-01-22T18:35:24.049900Z

that's exactly my problem now. I have an infinite loop i need to debug

2021-01-22T18:35:55.050400Z

might be easiest to call persistent! while debugging - that makes the next transient op blow up, but it prints clearly

2021-01-22T18:36:42.051300Z

(of course you can create a new transient to use in the place of the old one too)

xceno 2021-01-22T18:37:02.052Z

That's what I did for a while but I find it highly annoying when everything blows up while debugging I'd be ok with "copy-transient-and-print-it"

2021-01-22T18:37:04.052100Z

(unless you are bashing in place, which means you are using transients wrong and that's the likely cause of your bug)

2021-01-22T18:38:21.053400Z

(defn debug-transient [t message] (let [p (persistent! t)] {prn message p) (transient p)) - something like that should be safe, it gives you a new transient back to use with the same contents

2021-01-22T18:39:09.054400Z

the only reason you couldn't use that is if you are using the transient but not using the return value of conj! / assoc! etc., which, in this case, is the probably source of your bug

xceno 2021-01-22T18:40:48.056800Z

Hm fair enough, if the sort order remains the same that'll be good enough for now. I made sure to use the return value, so that's fine. The real problem is that I needed to translate a really hardcore imperative algorithm into clojure/fp and it's gotten real ugly (who would have thought)

2021-01-22T18:40:51.057Z

but more generally, I'd be suspicious of using transients for anything complex enough to need debugging - use normal collections then rewrite with transients when the tests pass

👍 1
xceno 2021-01-22T18:41:16.057600Z

Yes that's what I'll probably do now

2021-01-22T18:41:27.058Z

if you think transients will help you do an imperative algorithm, you're already on the wrong track

xceno 2021-01-22T18:42:11.058900Z

I've chosen them only for speed reasons, instead of an atom... I should have chosen the atom though it seems

2021-01-22T18:42:38.059400Z

the idea that a transient could replace an atom is already an error

2021-01-22T18:42:45.059700Z

they have the same api as normal collections, just different function names

2021-01-22T18:43:56.060700Z

they accidentally let you update in place, but that's not a defined behavior, it's just incidental - they are allowed to do so, and never promise to do so

xceno 2021-01-22T18:46:42.063300Z

Yes I found out afterwards and rewritten my code accordingly. But that's the thing. When I want to speed up code that is using an atom right now, I have to rewrite it anyway in order to use transients properly. So I figured I might as well go all in and write my algorithm only with transients. So yah, now I'm here, trying to debug things 🙂

xceno 2021-01-22T18:46:52.063600Z

but thank you, I'll try your debug snippet

2021-01-22T18:51:23.065500Z

@rob703 the thing that's meant to be an atom but faster is volatile! - but that only works in single threaded code

2021-01-22T18:54:37.068600Z

but, there's a pattern here - as with transients you get something more brittle and harder to debug, that has the same usage pattern

2021-01-22T18:55:10.069600Z

which means the effective way to use both is to use normal collections and container types first, get your code working, and if it's still too slow swap in a volatile! or transient if it's apropriate

xceno 2021-01-22T18:56:50.071100Z

I see, thank you. I'll keep that in mind as a hard earned lesson. I think my main problem was half-assing the translation from the oop/imperative to the clojure version. So I gotta clean that up now

kwladyka 2021-01-22T19:42:51.076900Z

Edit: moved to #ring

borkdude 2021-01-22T19:45:54.077400Z

@kwladyka I'm not sure if this question belongs in #clojure - also please don't flood the channel with JSON

borkdude 2021-01-22T19:46:49.077900Z

I mean, you can make this into a gist perhaps.

kwladyka 2021-01-22T19:46:57.078100Z

ok I will ask on #ring then

oliver 2021-01-22T21:01:45.079800Z

Hi! I want to build specs from a sequence of maps. Of course, spec/def being a macro, I cannot just map over the sequence. I could achieve it by using a macro myself, but I was wondering if it can be done with functions only. There is spec/def-impl, which is a function, but its docstring discourages its use… any ideas? (I'll totally take no for an answer.)

oliver 2021-01-23T18:36:28.173Z

Hi! Sorry, I only just noticed your message (I'm not that used to navigating slack). thats actually a great little piece of code, thank you that I will definitely add to my vault! (I'll not be able to use it for my immediate use case since eval is not available in ClojureScript afaik) Cheers!

John Conti 2021-01-24T21:26:02.259800Z

Glad I could offer something. I had forgotten about eval in Clojurescript, and I haven’t used it since the self-hosted compiler project started. So I had to ask duck duck go the state of play, and came across https://gist.github.com/mfikes/66a120e18b75b6f4a3ecd0db8a976d84. I know nothing about the viability of this implementation of eval. But it is a very exciting step in that compiler’s development that it can provide it. But other than enthusiasm I have no direct experience with it. Though functionalizing a macro seems like a good fit for it.

simongray 2021-01-22T21:06:38.080400Z

Try malli instead

oliver 2021-01-22T21:08:13.081600Z

Thanks, taking a look at it right now…

borkdude 2021-01-22T21:08:56.083300Z

@services yeah, there is no way doing that without a macro, or using the discouraged impl

2021-01-22T21:09:18.084300Z

technically it is possible, the most straightforward way being using eval

borkdude 2021-01-22T21:09:35.085100Z

yeah, macro or eval, kind of the same thing

2021-01-22T21:09:40.085400Z

in theory spec2 is supposed to make that sort of thing easier

2021-01-22T21:10:26.087100Z

but what I would do (and do all the time), is just write some code to generate the s/def forms, run that code in the repl, and then copy and paste those forms back in to your code

2021-01-22T21:10:35.087600Z

(assuming the maps are fairly static)

simongray 2021-01-22T21:11:39.091Z

It's a data-oriented Spec replacement, basically, made by metosin who also made spec-tools: https://github.com/metosin/malli

Grant Isom 2021-01-22T21:12:27.092200Z

Got a weird question: I am trying to format a request with Cheshire to have a key "\$oid" , but it only seems possible to get \\$oid. Is there a way to escape $ solely?

2021-01-22T21:13:11.093Z

you are likely being confused by printing at the repl

Grant Isom 2021-01-22T21:13:53.094200Z

When I actually send the request it still is \\$oid

2021-01-22T21:14:03.094500Z

how do you know?

2021-01-22T21:14:38.095500Z

there is no clojure syntax to escape $ in a string, because it's not special

2021-01-22T21:15:05.096Z

\ prints as \\ unless you are printing for display

2021-01-22T21:15:51.096800Z

user=> "\\$oid"
"\\$oid"
user=> (println "\\$oid")
\$oid

2021-01-22T21:17:03.097600Z

user=> (seq "\\$oid")
(\\ \$ \o \i \d)
user=>

Grant Isom 2021-01-22T21:17:53.098500Z

When I actually made the request, the key for the JSON object was still \\$oid

2021-01-22T21:18:24.099900Z

do you mean the it was serialized in the json that way?

2021-01-22T21:18:38.100600Z

because the same escaping happens in json

2021-01-22T21:18:54.101700Z

the string that prints normally (with println) as "\\$oid" would print for reading (with prn) as "\\\\$oid"

alexmiller 2021-01-22T21:18:58.101800Z

s/register can be used for this in spec 2

Grant Isom 2021-01-22T21:19:34.103200Z

I guess I am not trying to escape the dollar as I am trying to escape the slash. I need it to be received \$ because in another env I need to escape the dollar.

2021-01-22T21:20:15.104200Z

@grant.isom no clojure string will ever prn as "\" undoubled, and the repl uses prn

oliver 2021-01-22T21:20:32.104500Z

@hiredman, @borkdude Thanks to both of you! 1. I'm on ClojureScript, so no eval for me 😔 2. The Sequence is not static, since it is supposed to be edited by my customer who wants to compile the app on his own and generate different versions (we'll see how that works out). Altogether this is not super important, since I already have implmented a working macro-solution… just thought I might simplify it and gain a better understanding of spec @simongray Malli sure does look like an interesting choice fo my use case. One of my goals is to match an existing Swagger2 Schema… which apparently Malli schemas can be transformed into…

borkdude 2021-01-22T21:21:58.105800Z

@services swagger-like JSON API things is really where Malli probably shines

borkdude 2021-01-22T21:23:59.107100Z

as malli also supports coercions out of the box, and spec doesn't

borkdude 2021-01-22T21:24:09.107400Z

and for other reasons maybe too

Grant Isom 2021-01-22T21:26:04.109800Z

Okay found out cheshire was escaping my escapes haha

Grant Isom 2021-01-22T21:26:53.110500Z

Thanks @noisesmith and @hiredman!

oliver 2021-01-22T21:29:35.111800Z

@simongray, @borkdude Looks like the Malli Readme will be my bed-time reading for tonight…thanks! For the record: what I'm trying to do is to declare the constraints on my data in one place and then impose them on my API-request as well as on the input fields in my form (e.g. max-length attributes and field validation)

simongray 2021-01-22T21:32:23.113200Z

I haven't used Malli myself, only spec, but it seems like it would fit your use case.

simongray 2021-01-22T21:32:57.114Z

@services See also #malli

Danny Almeida 2021-01-22T22:56:22.118800Z

Hi everyone! Is there a guide or some sort best practises when it comes to deploying clojure apps to the cloud ? I'm looking at AWS and was wondering if there is some sort of step by step guide to the setup including jar/war creation, deployment and monitoring it... maybe even a CI/CD setup. I've a local docker based setup for experimentation, but I've not tried a production build/setup as yet. Any pointers in this direction would be appreciated. Thanks in advance 🙂

2021-01-22T23:00:55.119200Z

my best results always come from following instructions for java, but using lein or clj to build the fat jar instead of maven

1
borkdude 2021-01-22T23:00:56.119400Z

@dionysius.almeida This article appeared a while ago: https://circleci.com/blog/deploy-a-clojure-web-application-to-aws-using-terraform/ (since you asked about AWS)

2
1
2021-01-22T23:01:36.119800Z

this generalizes to google cloud, or desktop apps, etc.

Danny Almeida 2021-01-22T23:01:56.120Z

how do you deploy ? Do you use containers or something else ?

Danny Almeida 2021-01-22T23:02:49.120200Z

this is not for work...just experimenting as I'm doing a cloud certification course and wanted to do a clojure deployment as part of the learning process

2021-01-22T23:03:17.120400Z

that varies based on how devops should work

2021-01-22T23:03:32.120600Z

the simplest thing IMHO is to wrap the java service in a daemon

2021-01-22T23:03:59.120800Z

at a certain point of complexity, using docker or whatever plus a container mainagement infrastructure becomes simpler

2021-01-22T23:04:07.121Z

I've never seen that happen for a personal project

Danny Almeida 2021-01-22T23:04:28.121200Z

that's true. I'm loathe to setting up a EC2 instance and then install jdk etc and setting it up as that's a lot maintenance further down

2021-01-22T23:04:41.121400Z

you never need a jdk

Danny Almeida 2021-01-22T23:04:50.121600Z

i meant jre to run the app

2021-01-22T23:05:19.121800Z

right - but a good clojure app never needs more than the jar itself and a jre

2021-01-22T23:05:27.122Z

anything else means I'm probably doing it wrong

Danny Almeida 2021-01-22T23:05:40.122200Z

so what's the lightest setup you would recommend ?

2021-01-22T23:05:51.122400Z

(eg. depending on local resources in a fs when I should be using a service for storage)

2021-01-22T23:06:19.122600Z

the lightest setup is a fat jar, a jre, and a systemd script that starts java

borkdude 2021-01-22T23:06:21.122800Z

if you want "easy" you can maybe try Heroku. If you want complex (load balancers, Terraform, etc) look at the article I posted in the main channel.

2021-01-22T23:06:49.123100Z

yeah - I really don't like the heroku approach, they use git and lein on the server

Danny Almeida 2021-01-22T23:07:11.123300Z

@borkdude thank you, will check it out

2021-01-22T23:07:28.123500Z

I'm trying to suggest simple rather than easy or complex

Danny Almeida 2021-01-22T23:07:40.123700Z

i am looking at simple setup which can be scaled in and out based on workload

borkdude 2021-01-22T23:07:50.123900Z

I've been deploying personal projects as java -jar uberjar.jar and init scripts (now systemd, I guess)

💯 2
Danny Almeida 2021-01-22T23:08:02.124100Z

and have databases etc as managed services separately

2021-01-22T23:08:35.124500Z

yeah, sounds like you want some real infrastructure then - I haven't used terraform in anger but it's definitely meant to do what you want

2021-01-22T23:08:50.124700Z

it's a complex pile of brittle crap also (or else someone set it up badly...)

1
borkdude 2021-01-22T23:09:01.124900Z

you could also try datomic cloud. your app will live inside the db (as a managed service) ;)

Danny Almeida 2021-01-22T23:10:36.125100Z

ah i see .. that's interesting. But for experimentation, i would rather stay out of datomic cloud, as I've heard it's quite expensive and the setup is difficult as well

Danny Almeida 2021-01-22T23:11:01.125300Z

but thanks for all the tips guys 👍:skin-tone-3:

2021-01-22T23:11:27.125500Z

I haven't seen any mass scale app orchestration that isn't hard to set up and expensive - I think it kind of comes with the domain

Danny Almeida 2021-01-22T23:13:22.126100Z

@borkdude yeah that's what I want to do as well .. If you could share notes of your setup, that would be nice

borkdude 2021-01-22T23:14:33.126900Z

sorry, I removed the msg. I said: we are migrating from bare metal Docker swarm to AWS docker swarm

Danny Almeida 2021-01-22T23:15:18.127100Z

yeah i read that before you deleted it 😉 . thanks for the link you posted. Will go through it

borkdude 2021-01-22T23:15:22.127300Z

I haven't personally done this migration, so I don't have any notes right now. The reason we are moving away from bare metal has to do with someone leaving our team, so we have no choice

borkdude 2021-01-22T23:15:40.127500Z

but the bills will probably be a lot steeper

2021-01-22T23:16:22.127700Z

there are options with terraform to have config driven cluster spinup

1
Danny Almeida 2021-01-22T23:16:33.127900Z

i guess there is always a price for convenience 🙂

Danny Almeida 2021-01-22T23:17:21.128100Z

@noisesmith thanks .. will research terraform and docker options for deployment

2021-01-22T23:20:21.128400Z

another concern is that docker was not designed for security, newer kubernetes addresses this by using an alternative container format with a compatible config

1
Danny Almeida 2021-01-22T23:21:53.128600Z

@noisesmith i see. thanks for the tip

2021-01-22T23:22:17.128900Z

also, even with a container, it's still better to run your build tool and package a jar into the container, rather than making a container that runs your build tool on startup

Danny Almeida 2021-01-22T23:23:42.129100Z

i agree. that makes more sense

John Conti 2021-01-22T23:25:23.129300Z

(defmacro functionize [macro]
  `(fn [& args#] (eval (cons '~macro args#))))

(let [a [true]] (apply (functionize and) a))
=> true
https://stackoverflow.com/questions/9273333/in-clojure-how-to-apply-a-macro-to-a-list has always struck me as the least tortured way to deal with macros, by simply turning them into functions.

🙏 1