Fork me on GitHub
#beginners
<
2020-10-09
>
Dave Russell08:10:09

Hey all! Suppose I have a function:

(defn foo [] (cool-stuff :foo :bar :baz))
Is it possible to grab the quoted body of foo?
(first X) => cool-stuff
(second X) => :foo 
Where X somehow retrieves '(cool-stuff :foo :bar :baz) using only the var foo?

vlaaad09:10:22

it’s possible sometimes, unreliably 🙂

vlaaad09:10:08

You can read the source of a symbol pointing to a var, here is an example code: https://github.com/clojure/clojure/blob/master/src/clj/clojure/repl.clj#L147-L170

vlaaad09:10:02

then you can read-string the source

Dave Russell09:10:17

Hmm, maybe this is is a case of the X/Y problem 🙂 What I'm trying to do is write a test that pulls in a form, runs postwalk on it, and uses that info to run more tests. That way, when the original form is updated, the test will automatically enforce checks against the new changes. I had assumed that the question above was the best way to do it. Is there a better way you might know about? Appreciate the help!

Jim Newton09:10:05

what is the best way to non-destructively prepend a list of elements to another list, sharing the tail of the original list?

delaguardo09:10:53

concat ? but I don’t understand last part of the question, about sharing the tail

Jim Newton09:10:36

prepending n elements to a list of length 1 should take the same time as appending n elements to a list of length 1000000000000

Jim Newton09:10:51

and take the same memory

delaguardo09:10:00

(defn append-sharing-tail [l1 l2]
  (cons (first l1) (concat (rest l1) l2)))

Jim Newton09:10:37

and if l1 is empty, that won't work

Jim Newton09:10:02

but I think you meant a recursive call rather than a call to concat, right?

Jim Newton09:10:19

(defn append-sharing-tail [l1 l2]
  (cond (empty? l1) l2
        (cons (first l1) (append (rest l1) l2))))

delaguardo09:10:19

no, why you need recursion here?

Jim Newton09:10:40

because the call to concat does not share tails.

delaguardo09:10:01

why is that?

Jim Newton09:10:23

well if concat shares tails, then I don't even need append-sharing-tail, just call concat directly. right?

Jim Newton09:10:01

at least concat is not documented to be tail sharing.

Jim Newton09:10:20

when I look at the code for concat, even though I don't completely understand it, it seems that if the first list is empty, then the second list is returned.

mavbozo10:10:23

i've been bitten by concat , especially when the size of the lists are really large.

mavbozo10:10:37

use lazy sequence carefully

mavbozo10:10:14

above article really helps me on how to use lazy seq

mavbozo10:10:36

like (nth (iterate #(concat % [1 2 3]) [1 2 3]) 4000)

mavbozo10:10:49

; Error printing return value (StackOverflowError) at clojure.core/concat$fn (core.clj:725).

delaguardo10:10:28

last form returns correct result for me)

delaguardo10:10:43

and the outcome from mentioned article is not “do not use concat” it is “don’t mix lazy and strict”

noisesmith21:10:50

concat will use the original list as its tail, (structurally share) but also it wraps its own lazy thunk around it (which is where the stack bomb of nested concat calls comes in)

Jim Newton09:10:34

I can write this as a small recursive function of course, which works because I know my lists are small.

(defn append-sharing-tail [l1 l2]
  (cond (empty? l1) l2
        (cons (first l1) (append (rest l1) l2))))

Jim Newton13:10:33

the https://clojuredocs.org/clojure.core/distinct doesn't say whether the order is preserved given an ordered sequence. I.e., if a sequence, a, contains no duplicates is (= a (distinct a)) ? Or do I need to check whether the lengths are the same?

Jim Newton13:10:41

If I'm not mistaken, I think it is possible to write a faster uniquification function if I don't have to preserve the order.

Alex Miller (Clojure team)13:10:18

Order is preserved (as in all seq ops)

Karo15:10:20

Hi all, is it possible to extract route information from compojure route definition for example in case of these routes to get this data {:route1 "/:study_uuid/study_summary", :route2 "/:study_uuid/study_benchmarks"}. Thanks

(defroutes api-routes
  (GET (r-> "/:study_uuid/study_summary") [study_uuid] (get-study-summary study_uuid))
  (GET (r-> "/:study_uuid/study_benchmarks") [study_uuid] (get-study-benchmarks study_uuid)))

Dave Russell09:10:42

Let me know if you figure out a way to do this in compojure, I'm trying to do the same exact thing!

borkdude18:10:56

@vnazaryan I'm not sure. Maybe it would be good to look into something like reitit which is data driven rather than macro driven

👍 3
Nassin19:10:46

@vnazaryan, don't see why not, it's just a list you can manipulate

👍 3