Fork me on GitHub
#clojure
<
2018-01-14
>
noisesmith00:01:56

sente does websocket messages to/from core.async channels, but something that connects two programs has failure modes that core.async doesn't

Mikko Harju09:01:50

What’s the easiest way to make a string with quotes compatible for evaluation in the REPL? Spefically I have a JSON dict, {"event":"complete","created":"2018-01-12T15:36:46+0200","data":{"id":418}} and would like to parse it to a Clojure data structure. Typically I’ve just put it in VIM and search-replaced quotes with \” but that seems overly complicated?

Mikko Harju09:01:46

Ah, read-line would work 🙂

Mikko Harju09:01:00

So just (json/read-str (read-line)) and we’re done.

cvic13:01:07

Awesome chapter http://aosabook.org/en/500L/an-archaeology-inspired-database.html > Since we are building a functional database, we will be using a functional programming language called Clojure. > Clojure has several qualities that make it a good implementation language for a functional database, such as out-of-the-box immutability, higher order functions, and metaprogramming facilities. But ultimately, the reason Clojure was chosen was its emphasis on clean, rigorous design, which few programming languages possess.

zsck17:01:31

I have spent the last several days studying Clojure and playing around with some libraries to do a tiny bit of web development. In general, I'm finding the language very fun to use and excellently designed. However, I am a bit hesitant to continue studying it for the following reasons: 1. I've never had to develop anything to run on the JVM or on .NET. 2. I do mostly backend development, where Clojure could certainly shine, but I also do a lot of tool development where my code has to be run in environments where neither host (JVM or .NET). 3. I hate to beat a dead horse, but the error messages are really not good, especially compared to those emitted by my main alternatives, Rust, Elm and even Go. 4. I don't work on large enterprise-y teams, but typically in environments where people are much more likely to feel they get value from something like Rust or Go, but not so much from a JVM-hosted language. Convincing people to learn a Lisp is hard in my experience. So while Clojure could absolutely fill a place in my stack and I'd be excited to have it do so, these problems make me think that Clojure may, very unfortunately, simply not be the tool I'm looking for. Based on this, would you folks agree, or are there things I could consider to address some of these concerns?

bbloom17:01:41

@zack.mullaly I don’t know who your patrons are, but unless they have deep pockets and even more patience, it doesn’t make sense to bet on significantly unknown (to you at least) tech with their time and money

bbloom17:01:23

spend some time on your own, either personal time, or explicitly carved out business time, to learn clojure/jvm/whatever and maybe you’ll find it fills some need & the risk/reward makes sense. but otherwise, go with what you know

manutter5117:01:33

@zack.mullaly You might want to check out planck and lumo and see how they might fit into your tool-development needs. They may or may not be a good fit for you, but they're worth a look

rauh18:01:20

Has somebody written some hacks/tools that prints seqs/vecs with the type they actually are? Ie, something like (map inc [0 1 2]): would print #LazySeq[ChunkedCons [(0 1 2), nil]] or so

Alex Miller (Clojure team)20:01:28

You can overload various print multimethods to do this if you like. Generally if your code cares then that’s prob a smell

itaied20:01:04

Does clojure spec replace the use of records for modeling domain data? I'm reading Clojure Applied, where the author model the domain data using defrecord, but it looks like spec actually does the same thing with much more features and flexibility.

Alex Miller (Clojure team)20:01:52

I’m the author and I would probably lean more heavily on maps and spec now

schmee20:01:28

they solve different problems. a very short summary is that spec allows you to describe the format of your data, while records allow you to get higher performance and use polymorphism through multimethods

rauh20:01:28

@alexmiller I see. I was hoping somebody possible already did the work. I'm trying to learn more about the internals in Clojure. Follow up Q: Is it intentional that a reduce once "stuck" in naive-seq-reduce will never escape back to a faster reduce implementation? Eg. a (reduce + 0 (cons 1 some-very-very-large-vec)) will stay in a first/next reduce (AFAIKT).

itaied20:01:05

@schmee records aren't used for describing the data as well? I read that records are actually just maps with the ability to implement interfaces

itaied20:01:35

Is there any integration between them that is popular to design by?

schmee20:01:22

records can be used to describe data, but AFAIK they should not be used like Java classes, i.e. don’t make a record for each of your data types unless you are actually using them for multimethods/polymorphism

schmee20:01:58

it’s a bit more complicated than that: check out https://clojure.org/reference/datatypes for a detailed explanation 🙂

schmee20:01:55

“integration between them” <- you mean between records and spec?

itaied20:01:33

@schmee I'm still trying to figure out when should I model that data for simple web apps, since the modeling already happens in the api endpoints and db tables... And yes I meant record and spec, is there any fundamental support or it's up for the developer to validate the spec?

schmee20:01:23

IMO, if you don’t need the performance or polymorphism, go for maps + spec, it’s the standard approach 🙂

itaied20:01:16

Yea that's what I thought, just trying to figure out all the pieces

seancorfield21:01:38

@zack.mullaly Late following up on your comments but I'd say much of Clojure out there is in small, agile teams -- and the JVM is no obstacle at all.

qqq21:01:57

this is a piece of work in progress, would love criticism / thoughts / ideas on how to make it better: goal: build a mini DSL for converting DSL/Sexp into cuda kernels (written in C) // not targetting all of clojure

(declare sexp->cu)

(let [f sexp->cu] 
  (def fns
    {:arr  (fn [base idx] (a/strf "(%s[%s])" (f base) (f idx)))
     :+    (fn [lhs rhs] (a/strf "(%s+%s)" (f lhs) (f rhs)))
     :*    (fn [lhs rhs] (a/strf "(%s*%s)" (f lhs) (f rhs)))
     :do   (fn [& lst]
             (a/strf "{%s}" (apply str (map f lst))))
     :if   (fn
             ([tst tc  fc] (a/strf "if %s %s %s" (f tst) (f tc) (f fc)))
             ([tst tc] (a/strf "if %s %s" (f tst) (f tc))))
     :set! (fn [lhs rhs] (a/strf "%s=%s;\n" (f lhs) (f rhs)))}))

(defn sexp->cu [sexp]
  (cond
    (symbol? sexp) (str sexp)
    (number? sexp) (str sexp)
    (list? sexp)   (apply (fns (keyword (first sexp))) (rest sexp))))

(is (= (sexp->cu 23) "23"))
(is (= (sexp->cu 'abc) "abc"))
(is (= (sexp->cu '(arr a b)) "(a[b])"))
(is (= (sexp->cu '(+ a b)) "(a+b)"))
(is (= (sexp->cu '(set! a (+ b c))) "a=(b+c);\n"))
(is (= (sexp->cu '(if a b)) "if a b")) 
(is (= (sexp->cu '(if a b c)) "if a b c"))

seancorfield21:01:34

@qqq There's a #code-reviews channel...

seancorfield21:01:02

(just sayin', since I'm not sure many people know about it)

qqq21:01:04

@seancorfield ah, will post there in the future

qqq21:01:21

I was complaining here quite a bit in past weeks about lack of decent "clojure dsl -> C / wasm" tools, and thought others may be interested now that I'm starting to write a mini one myself

itaied21:01:11

https://stackoverflow.com/q/48247730/3648107 Would like to hear your thoughts, as stack overflow didn't find the question too interesting...

samcgardner21:01:30

So let's take the case you use of sortedness

samcgardner21:01:42

We can write a function that tests a list is sorted without implementing sort

samcgardner21:01:57

And then test that isSorted(sort(a)) == true

samcgardner21:01:26

You could test sort a != nil (you probably don't want to accidentally return nil anywhere, right?)

samcgardner21:01:30

Or that it contains all the elements of a

samcgardner21:01:54

Or that your sort is stable (if I have elements a1 and a2 with equal sorting order, they stay in the order they are currently in)

samcgardner21:01:02

None of those things require you to implement sort

itaied21:01:56

How can you tell you wrote`is-sorted` correctly? Would you write a test for that as well? I mean, when the predicates are getting more complex, we have to use more advanced logic, and therefore more code.

seancorfield22:01:58

@itaied I wouldn't consider property-based testing as a replacement for (example-based) unit testing. They have very different characteristics.

samcgardner22:01:12

At some point you have to assume you can implement some predicates correctly

samcgardner22:01:36

I think a good property is a) provided by fiat (this property is complicated to prove, but I'm going to believe it holds because I'm trusting that this battle-tested software library implements it correctly) or b) simple enough that you're confident in your implementation. I wouldn't hate testing predicates if you feel you should but my intuition is that you shouldn't need to very often

qqq22:01:12

I've found "automatically generate unit tests" to be time consuming, mentally draining, and in general, hard to use. What I have found to be useful is: 1. write short functions that compose nicely 2. write a few unit tests that hit all 'branches' of the function Although theoretically unsound, in practice, I have found that if a branch of code does the right thing on one example, it probably does the right thing on all examples -- the reason being that these branches of code are not malicious/adverbial -- they're well intended pieces of code designed to do X, so the point of unit testing is just to catch silly typo-level errors

seancorfield22:01:38

@qqq Agreed that trying to come up with properties that hold for all input/output on a lot of functions is very hard.

seancorfield22:01:21

But property-based testing will often uncover bugs in edge cases, even when your example happy-path tests pass.

qqq23:01:36

For 'properties' I find it's often easier to code them up as assertions. For property based testing, atleast in my experience with spec, writing generators is insanely hard ... either I don't do anything smart, and the 10000 cases it generates are worthless, or I spend hours wracking my brain trying to think of a clever algorithm to test a variety of edge cases -- in which case, it's 100x easier to just write the edge case myself.

Alex Miller (Clojure team)01:01:37

you can enumerate edge cases in a generator by just using a literal set and this is a good and useful technique to use in combination with a random generator

qqq23:01:20

===== #(f (first %1) (second %1)) is there any chance we can rewrite this as #(f %1.1 %1.2) ? I find that I often have a situation where: f :: [a, b, c] -> ... then I want to do (map f lst) but that doesn't work since lst is givine me one elem at a time, so I end up writing (map #(f (first %) (second %) (third %)) lst)) but I would much rather just write (map #(f %1.1 %1.2 %1.3) lst)) [ I reailze I can write (map #(apply f %) lst) -- but sometimes I have to reorder args ]