beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
2021-06-08T00:33:54.399500Z

What’s happening here? I’m trying to install the REBL and I get this:

cognitect-dev-tools-0.9.58 % bash ./install
Installing: com.cognitect/rebl {:mvn/version "0.9.242"}
./install: line 5: mvn: command not found
Installing: com.datomic/dev-local {:mvn/version "0.9.232"}
./install: line 7: mvn: command not found

alexmiller 2021-06-08T00:35:18.400100Z

Looks like you need to install Maven (mvn)

1👍
2021-06-08T15:01:04.414Z

Thank you, I ran brew install maven and it worked 🙌

popeye 2021-06-08T07:16:30.401300Z

i was referring clojure book and I come across (def app (middleware/wrap-base #'app-routes)) , what does #` do here?

popeye 2021-06-08T07:29:45.401600Z

here app-routes are list of routes

popeye 2021-06-08T07:30:12.401900Z

why we cannot use as (def app (middleware/wrap-base app-routes))

seancorfield 2021-06-08T07:36:09.402100Z

You can but without the var quote, if you change app-routes while you app is running in the REPL, that change will not be seen.

1✅
seancorfield 2021-06-08T07:36:32.402500Z

With the var quote, there’s an extra level of indirection, so changes made by the REPL take effect without a restart.

seancorfield 2021-06-08T07:37:04.402700Z

See https://clojure.org/guides/repl/enhancing_your_repl_workflow#writing-repl-friendly-programs (that whole guide is worth reading).

popeye 2021-06-08T07:52:37.402900Z

@seancorfield, I got that, but that wont be helpful while running code in production right? because production code will be freezed

Juλian (he/him) 2021-06-08T08:02:28.404600Z

is there an easier way to apply a list of functions (with side-effects) to a map? the way I came up with: (reduce (fn [state f] (f state)) initial-state function-list)

Juλian (he/him) 2021-06-12T19:56:36.106500Z

btw, I reverted back to the reduce function from the beginning, because I got stack overflows when there were too many functions

seancorfield 2021-06-08T08:29:03.405Z

You want the behavior in dev.

1🙌
popeye 2021-06-08T08:29:57.405300Z

Thanks @seancorfield

seancorfield 2021-06-08T08:29:57.405500Z

But you can also have that behavior in production if you want. We run REPLs in some of our production processes and modify them live, while they are running.

pavlosmelissinos 2021-06-08T08:40:48.405900Z

How about (doall ((apply comp (reverse function-list)) initial-state)) ? edit: added missing parens

pavlosmelissinos 2021-06-08T08:41:36.406100Z

I don't have a repl in front of me right now but I think that would also work

Juλian (he/him) 2021-06-08T08:58:41.406500Z

thanks

Juλian (he/him) 2021-06-08T09:06:38.406700Z

didn't think about comp, it does make it easier

1😉
Juλian (he/him) 2021-06-08T09:12:47.407100Z

is the doall necessary? the function-list is lazy, but applying comp returns a function that shouldn't be lazy

Juλian (he/him) 2021-06-08T09:15:00.407300Z

also, since my function-list is symmetrical, I'll leave out the reverse - leaving a short and nice ((apply comp function-list) initial-state) - thanks for your help!

pavlosmelissinos 2021-06-08T09:21:41.407500Z

> applying comp returns a function that shouldn't be lazy Not so sure about this to be honest :thinking_face:

pavlosmelissinos 2021-06-08T09:34:34.407700Z

Ah, it seems you're right!

(->> (range 12)
     (map (apply comp
                 [#(do
                     (println "Realized" %)
                     (- %))
                  #(+ 1 %)
                  #(* 2 %)]))
     first)
evaluates to -1 but prints:
Realized 1
Realized 3
Realized 5
Realized 7
Realized 9
Realized 11
Realized 13
Realized 15
Realized 17
Realized 19
Realized 21
Realized 23

popeye 2021-06-08T13:02:08.409200Z

how to convert all the values from an map to string in clojure i have map like {:1 one :2 two} to {:1 "one" :2 "two"}`

2021-06-08T13:16:00.409500Z

strait forward solution is to use reduce-kv

(reduce-kv
 (fn [acc k v]
   (assoc acc k (str v)))
 {}
 {:x 1 :y 2})
but it wouldn’t help if you have a map with nested maps. if that is the case you could use recursion

popeye 2021-06-08T13:17:57.409700Z

yeah that works!!!any inbuilt function available in json ? I got :`key-fn` but did not get how it is used

2021-06-08T13:21:44.409900Z

depends on underlying library. I think jsonista has some functionality to add custom encoder/decoder

2021-06-08T14:11:02.411100Z

Documenting some of my early experiences learning Clojure. A caveat is that this is my first general purpose language that I’m really getting into (I tried teaching myself Python a few years back but got bored with that, probably because I didn’t have much of a goal at the time) https://twitter.com/RobertHaisfield/status/1402249772543614976?s=20

Yair Taboch 2021-06-08T14:26:59.411300Z

(into {} (map #(vector (first %) (str (second %))) {:1 :one :2 :two}))

1✅
2021-06-08T14:34:13.411600Z

Does anyone know any good animations that show how `apply` works in Clojure? Something like these? https://jstutorial.medium.com/map-filter-and-reduce-animated-7fe391a35a47

dpsutton 2021-06-08T14:45:13.412300Z

You asked this yesterday and got some great responses from really knowledgeable people. Not sure what else there is to say if you don't have a specific question about apply

thomas 2021-06-08T14:45:20.412400Z

Forgive me if this question is beyond me as I am not very versed in clojure but, do you mean like behind the scenes/how its implemented or something? Conceptually I think apply might be easier to understand by just remembering that:

; this:
(apply + (list 1 2 3 4 5))

; is the same as this:
(+ 1 2 3 4 5)

thomas 2021-06-08T14:53:00.412600Z

this doesn't exist in most other languages because they dont have s-expressions but I guess this kind of looks like it does the same as reduce until you understand that it it isnt (see above). the way I think of it is that it is a convenience function that exists because some times its nice to have. like the identity function. doesnt make much sense as to why it exists (to me at least) until you need it.

2021-06-08T14:55:29.413200Z

@dpsutton Oh wow I totally missed those. I’m used to Slack channels where people respond in threads vs. just in the channel, my bad

2021-06-08T14:55:35.413400Z

I’m gonna look back over them

2021-06-08T14:58:44.413800Z

This seems like the sort of tool I need to explore a lot

2021-06-08T15:01:04.414Z

Thank you, I ran brew install maven and it worked 🙌

2021-06-08T15:02:27.414200Z

So is apply basically bursting the arguments out of the list they were in?

2021-06-08T15:07:34.415300Z

The concept of apply is clearer to me now, so I guess I’m closer to figuring out how I would visualize it… still can’t find any examples of it animated

thomas 2021-06-08T15:07:50.415500Z

it just takes the function given as the first argument and "applies" it to the list given as the second argument.

thomas 2021-06-08T15:09:22.415700Z

in lisp terms you just stick the first argument at the front of the second argument which is a list, easy as

thomas 2021-06-08T15:12:05.415900Z

user=> (apply + '(1 2 3 4 5))
15
user=> (+ 1 2 3 4 5)
15
I think it might be confusing because: a) it looks like it does the same thing as reduce:
user=> (reduce + '(1 2 3 4 5))
15
b) it doesn't exist without s-expressions but its really simple (at least conceptually), dont overthink it 🙂

2021-06-08T15:56:45.416100Z

comp returns a lazy function when the first function arg is lazy

2021-06-08T15:57:17.416400Z

whether you apply it to a lazy arg is irrelevant as it eagerly consumes its args

2021-06-08T15:59:01.416600Z

@pavlos your example from map isn't showing what you think it is - map is lazy (even here) but laziness across some data types (like vectors and ranges) is chunked - chunking means that realizing one item means realizing n items (where n is usually 32)

pavlosmelissinos 2021-06-08T16:00:42.416800Z

Ah, I knew about chunking but I thought n was something like 8. Didn't think to test with a larger input, thanks 🙂

2021-06-08T16:02:33.417Z

funny thing, when I run that code but change (range 12) to (range) it only realizes the one item, I wonder what trickery is going on there

2021-06-08T16:02:55.417200Z

perhaps (range) doesn't have the chunking behavior that (range n) does

2021-06-08T16:04:05.417400Z

if I give it (range 1000) it stops at 63 which is the 32nd result

2021-06-08T16:04:16.417600Z

so yeah, chunked by 32

2021-06-08T16:04:34.417800Z

but don't count on that number in your code - just account for the fact chunking of some N is possible

2021-06-08T16:05:08.418Z

anyway none of this is related in any way to comp

2021-06-08T16:06:25.418200Z

my version: (into {} (map (juxt (comp identity key) (comp str val))) m)

2021-06-08T16:08:53.418500Z

almost like @yairt’s but notice that map is being called with only one arg, and I use key / val instead of first / second

popeye 2021-06-08T16:10:24.418800Z

I tried https://github.com/clojure/data.json

2021-06-08T16:10:55.419200Z

how would I animate the application of a function to args? it's not multi step, it's a single event

2021-06-08T16:12:32.419600Z

thinking it through.... (apply + 1 2 [3 4 5]) becomes (apply + [1 2 3 4 5]) which finally becomes (+ 1 2 3 4 5) I don't think there's more than that you could demonstrate - would an animation with those three steps actually help?

popeye 2021-06-08T16:12:35.419800Z

@rob370 Any documentation for apply.. I am trying to understand it ..

popeye 2021-06-08T16:12:57.420Z

did not get when compare to reduce and map

2021-06-08T16:13:07.420200Z

it's not in the same category with those at all

2021-06-08T16:13:14.420400Z

it takes a function and args and calls the function

2021-06-08T16:14:31.420600Z

maybe my three step example above helps? maybe it doesn't. note that the simplification I show is conceptual and not reflecting the actual code - it's very low level clojure code that implements it

2021-06-08T16:15:59.420800Z

@popeyepwr perhaps the source of your confusion is that for associative functions like + and * and conj using apply and using reduce happen to return the same result? that's not something special about apply, that's something special about those functions and how they treat their args

2🎯
2021-06-08T16:16:00.421Z

Perhaps an animation could show the apply and the brackets around [3 4 5] fading away

2021-06-08T16:16:57.421200Z

interesting - I guess I internalized this so long ago I lost my intuition for what is counter-intuitive when first learning it 😄

2021-06-08T16:19:40.421400Z

I guess that middle step I provided is arbitrary, and arguably should be skipped, I wanted to highlight the vararg behaviour of apply because I've seen too many experienced clojure users do things like (apply f (concat [a b] other-args)) where (apply f a b other-args) already works

2021-06-08T16:20:36.421600Z

but that's more intermediate to journeyman level rather than beginner level

2021-06-08T16:21:35.421800Z

Yeah broadly speaking I’m really interested in tooling around “learnable programming” to help people understand what’s actually happening. From what I can tell, once people pick up the mental models they don’t struggle to visualize things in their heads but things like Reduce and Apply are pretty foreign to me (a brand new programmer)

2021-06-08T16:22:18.422Z

One possibility I’m exploring is a more interactive REPL that could visualize things like this so people can have a visceral sense for how a function executes

2021-06-08T16:22:32.422200Z

data.json is soemthing totally different - it turns the whole hashmap into a string that javascript can parse

2021-06-08T16:23:55.422400Z

I’ve worked on the onboarding experience for GuidedTrack (a domain-specific language meant for non-programmer researchers and educators) and it has made me more confident in the idea of domain-specific languages as a vehicle for end-user programming and maybe even an alternative to traditional apps. Clojure is my first general purpose language I’m learning! https://www.youtube.com/watch?v=ov3lynWp9oM&t=13s

2021-06-08T16:25:43.422700Z

that's cool. one thing to note is that clojure is intentionally "a language for experts" and in any design conflict between intuition for beginners and flexibility / optimal behavior for experts, the experts will win. there's at least one youtube talk where Rich describes this in length, I'm looking it up now

2021-06-08T16:26:31.422900Z

I've even told people in the past clojure is a bad first language (don't let this stop you if you enjoy clojure of course)

pavlosmelissinos 2021-06-08T16:29:48.423100Z

Yeah, not sure what I was thinking there with map. So whether this is lazy or not: ((apply comp (reverse function-list)) initial-state) depends solely on whether the last function in the function-list is eager or lazy, right?

2021-06-08T16:32:38.423800Z

right, reverse makes it more complex, but yeah, comp is never lazy, the laziness of the function comp returns is determined by the first function in its arg list

2021-06-08T16:33:19.424Z

in general, laziness in clojure is a behavior of a data type, and a function is lazy if it returns one of those lazy types

2021-06-08T16:34:03.424200Z

and comp's return type is the return type of its first arg (this shouldn't be hard to figure out by first principles)

2021-06-08T16:38:29.424400Z

Yeah that’s fair that it’s designed as a language for experts. I think in general I’m not interested in modifying the language so much as just making more intuitive and obvious tooling around it and I think that Clojure’s generally uniform syntax opens up a lot of possibilities. Racket is another target for the sort of stuff I’m working on. Macros may ruin all of my plans lol

2021-06-08T16:40:03.424600Z

When I first started playing with Clojure, its generally uniform syntax made it way less intimidating for me than Python was when I attempted learning that a few years back

2021-06-08T16:46:27.424800Z

if you get overwhelmed by the special cases and corner cases of clojure, scheme shares the simplified syntax and is also explicitly made for beginners / education. the racket version in particular has the best docs I've ever seen for any programming language

2021-06-08T16:46:51.425Z

but unlike clojure it doesn't have the conveniences for enterprise software, so it hasn't taken off in the industry

2021-06-08T16:47:11.425200Z

but so far it doesn't sound like you are at all interested in enterprise software

2021-06-08T16:47:46.425400Z

not telling you you are in the wrong place, but rather mentioning the kind of thing that comes up in my experience for people coming to clojure the way you are

2021-06-08T16:48:28.425600Z

racket definitely has the sorts of visualization of program steps you are talking about here in its IDE

sova-soars-the-sora 2021-06-08T16:49:00.426Z

I think sometimes apply and reduce will give the same result

2021-06-08T16:49:01.426100Z

(and, big picture, apply and reduce and map work the same way in clojure and in racket)

2021-06-08T16:49:50.426800Z

right, but that's a property of the function itself not a property of reduce / apply

2021-06-08T16:49:56.426900Z

Haha yeah I’m not personally interested in a career in enterprise software. I’m interested in replacing basic app functionalities with higher order functions so people can do the sort of stuff they were already interested in doing but with control flow and recursion to give them more flexibility over what a traditional GUI app would

2021-06-08T16:50:43.427200Z

yeah, racket is meant for that kind of thing

2021-06-08T16:51:06.427700Z

but please do continue using clojure, it's a great language 😄

2021-06-08T16:51:26.428300Z

And then providing tooling around those DSLs so people ramp up in skill level towards just writing fluently

pavlosmelissinos 2021-06-08T16:51:48.428900Z

That clears it up quite a bit, thanks.

2021-06-08T16:52:17.429100Z

Yeah Racket is definitely more purpose built for the sort of thing I’m interested in, it just seems more niche. I’ve made a basic program in it, and I just need to learn the different sorts of data structures

sova-soars-the-sora 2021-06-08T16:53:11.429500Z

I guess I don't really grok the difference yet

2021-06-08T16:53:15.429600Z

oh yeah, that's some historical baggage from the lisp family (it's simpler to just use lists for everything right???)

2021-06-08T16:53:25.430Z

One dilemma was basically: Clojure is built with smart defaults that will help me form a basic mental model. Racket has an encouraged style but is more agnostic. So I wasn’t sure if I should start out by forming my default mental models around Clojure mental models or by forming my own models from working with Racket

sova-soars-the-sora 2021-06-08T16:53:28.430200Z

but I will do some more reading ^.^ probably best just to see lots of examples

2021-06-08T16:53:39.430300Z

there are libraries that add data types to racket but most racket examples and code are going to be lists, lists and more lists

2021-06-08T16:54:30.430500Z

that's an interesting perspective, I definitely "leveled up" in software design by understanding clojure's design decisions

2021-06-08T16:55:17.431200Z

Yeah. Clojure does a lot of clever things to infer parentheses over pairs of things where Racket would make you manually specify them. I like how in Clojure the [ ] and { } indicate different types of things than the lists, but ultimately mean the same thing as (vector ) and (hashmap ). Makes it easier to visually parse.

sova-soars-the-sora 2021-06-08T16:55:23.431500Z

Okay apply is variadic and takes potentially many args Reduce must take a function of two inputs... and then args is that right?

2021-06-08T16:55:28.431600Z

another thing to look into (also another input to clojure's design) is the ml family (OCaml being the biggest living example) which tends to create too many data types instead of having too few

2021-06-08T16:56:04.432200Z

the variadic part is a distraction for your question

2021-06-08T16:56:32.432800Z

reduce walks one function across many items

2🐝2
2021-06-08T16:56:49.433300Z

apply calls one function with a list of args

2🍢
2021-06-08T16:56:54.433500Z

that's literally the whole thing

2021-06-08T16:57:45.434900Z

now, as an incedental thing, there are "associative" functions which act the same with apply and reduce, that's because someone constructed the function that way

2021-06-08T16:57:48.435200Z

it's not a property of apply or reduce

sova-soars-the-sora 2021-06-08T16:58:16.435300Z

Cool. I am looking at this example https://clojuredocs.org/clojure.core/reduce#example-542692ccc026201cdc326c40 for calculating primes and it is pretty awesome, I don't understand the (map (partial mod ...) part although I think I know what it's supposed to do

2021-06-08T17:00:09.435700Z

Also, the fact that functions are designed to abstractions is a tool for experts that I think also makes a beginner’s life easier.

sova-soars-the-sora 2021-06-08T17:00:29.436100Z

I need more practice using map and partial

sova-soars-the-sora 2021-06-08T17:00:36.436300Z

seems like a powerful combo

2021-06-08T17:01:03.437300Z

partial is just a stylistic alternative to fn or #() really

1💯
Antonio Bibiano 2021-06-08T17:01:49.438200Z

(partial func fixed-arg) will return a function that is like calling func with the first argument set to fixed-arg

2021-06-08T17:02:00.438300Z

oh that's not the aspect I think of as expert oriented

2021-06-08T17:02:38.438500Z

I'm thinking of the complexity around java interop, type hinting, chunking of lazy sequences...

sova-soars-the-sora 2021-06-08T17:02:46.438900Z

Oh neat. I did not think of it that way!

sova-soars-the-sora 2021-06-08T17:03:05.439200Z

so a partially determined anonymous function

2021-06-08T17:03:48.439300Z

re-listening to that talk I linked: "instruments are made for people that can play them, but beginners are not players yet"

2021-06-08T17:04:06.439500Z

"should we make cellos that auto-tune?"

Antonio Bibiano 2021-06-08T17:04:31.440100Z

yeah if you look at the source code for it it's also using apply 😄

sova-soars-the-sora 2021-06-08T17:05:54.440300Z

neat

2021-06-08T17:07:12.440400Z

"I don't think we should go to our tools and orient them to the first five seconds of usage"

Antonio Bibiano 2021-06-08T17:08:04.441200Z

I'm just wondering why in the source it is defined explicitly for up to 3 arguments

2021-06-08T17:09:13.442100Z

that's a performance optimization

Antonio Bibiano 2021-06-08T17:09:37.442800Z

ah interesting

2021-06-08T17:09:42.443Z

it's ubiquitous in clojure's core code, to break up arg counts so the method bodies and call stacks are smaller

Antonio Bibiano 2021-06-08T17:09:43.443100Z

to avoid the apply and the concat

2021-06-08T17:09:57.443500Z

right

Antonio Bibiano 2021-06-08T17:11:14.444500Z

I see.. because my first instinct would be to specify just the minimum needed

2021-06-08T17:11:44.445100Z

right, that's good code design when you are not in a bottle neck for performance, to have the smallest simplest code you can

2021-06-08T17:11:49.445400Z

I’ll check out the talk. I think that’s totally fair! I just don’t think those goals are mutually exclusive. Sometimes those design choices are going to work out for both experts and beginners, and sometimes tooling can be made around expert systems that make them easier for beginners. I see a lot of people using tools like Notion and Roam at extremely advanced levels, and think those people might benefit from something that ramps them up into programmability, which should ramp people up towards expert usage

2021-06-08T17:11:54.445700Z

but clojure.core is in every clojure user's speed bottleneck

Antonio Bibiano 2021-06-08T17:13:07.446400Z

makes sense, thanks for the explanation

2021-06-08T17:13:16.446500Z

GuidedTrack code basically parses to a JSON that gets interpreted by JS, but I’m imagining something that’s generally as simple as GuidedTrack in terms of the verbs (function operators) and syntax (basically just nested stuff within a structural editor) but gives access to the full programmability of a language like Clojure

2021-06-08T17:13:43.446700Z

right, I'm not arguing for that approach, just warning that this is the philosophy behind clojure's implementation and it can bump up against your interests

2021-06-08T17:14:25.446900Z

it's a conflict I've seen multiple times, so I'm helping manage expectations up front 😄

2021-06-08T17:15:53.447100Z

I appreciate that 🙂️ in making learnable programming tooling, I generally consider it valuable that I’m a behavioral product designer approaching programming fresh and naive, but I definitely rely on experts to tell me where my expectations are totally out of whack

2021-06-08T17:18:52.448200Z

I’m trying to learn from the history of what’s been tried moreso than get discouraged by it 😅

2021-06-08T17:19:47.449200Z

is there a way to use conditions as the final arg list to condp here? the idea is that the map will be used somewhere else, too, so I’d like to avoid duplicating them

(let [conditions {1 "Only one" 2 "Truly two"}
      v          1]
  (condp = v 1 "Only one" 2 "Truly two"))

2021-06-08T17:20:32.450100Z

you'd probably enjoy this talk from strange loop 2019 about teaching programming (and what mainstream cs eduction gets wrong) https://www.thestrangeloop.com/2019/how-to-teach-programming-and-other-things.html

1🙏
2021-06-08T17:20:55.450800Z

(conditions v)

1💯
2021-06-10T16:12:26.023500Z

@jeffrey.wayne.evans because it doesn't need to create a function for each example, and also because it doesn't need to create a lazy seq to provide args to some-fn

1👍
indy 2021-06-08T17:21:53.451700Z

Everytime I try to use generative tests, I get stuck at the very first step which is to decide on the "properties" that I should be testing, and how I should be generating them programmatically. The fundamental question in my head is this: aren't the functions that I'm going to write to assert the properties going to be very much the same as the function that I am about to test itself? https://grep.app/search?current=4&q=test.check&filter[lang][0]=Clojure. https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-006-introduction-to-algorithms-fall-2011/lecture-videos/MIT6_006F11_lec01.pdf. Can I use test.check for this? Can someone think of properties that are anything other than the property that the peak is actually a peak?

(defn mid-idx [start end]
  (+ start (int (/ (- end start) 2))))
  
(defn peak-finder-1D
  ([v]
   (peak-finder-1D v 0 (dec (count v))))
  ([v start-idx end-idx]
   (when (<= start-idx end-idx)
     (let [mid-idx             (mid-idx start-idx end-idx)
           maybe-peak          (get v mid-idx)
           left-of-maybe-peak  (get v (dec mid-idx))
           right-of-maybe-peak (get v (inc mid-idx))]
       (cond
         (nil? left-of-maybe-peak)
         [mid-idx maybe-peak]

         (nil? right-of-maybe-peak)
         [mid-idx maybe-peak]

         (and (>= maybe-peak left-of-maybe-peak) (>= maybe-peak right-of-maybe-peak))
         [mid-idx maybe-peak]

         (< maybe-peak left-of-maybe-peak)
         (peak-finder-1D v start-idx (dec mid-idx))

         (< maybe-peak right-of-maybe-peak)
         (peak-finder-1D v (inc mid-idx) end-idx))))))

2021-06-08T17:21:59.451900Z

ah right, since it’s simple equality this would work

2021-06-08T17:22:03.452200Z

the real case is more involved

2021-06-08T17:23:33.452500Z

(let [conditions {#"^foo.*" "Some foo" #"^bar.*" "Some bar"}
      v          "bar-value-1"]
  (condp re-matches v #"^foo.*" "Some foo" #"^bar.*" "Some bar"))

2021-06-08T17:23:34.452700Z

since condp is a macro, you'd need a data structure known at compile time and another macro

2021-06-08T17:24:43.452900Z

you could probably do something more complex with some-fn and functions that return a result on regex match or nil otherwise

alexmiller 2021-06-08T17:25:10.453100Z

property testing is easy. the only hard parts are the properties, and the generators. 😎

alexmiller 2021-06-08T17:26:40.453600Z

^^ that's a great article

alexmiller 2021-06-08T17:27:32.453800Z

I often look for the “Hard to prove, easy to verify” as a way to avoid rewriting the original code

2021-06-08T17:27:34.454Z

ah, that’s a good idea

2021-06-08T17:27:54.454200Z

(let [conditions {#"^foo.*" "Some foo" #"^bar.*" "Some bar"}
      v          "bar-value-1" 
      preds (map (fn [[re result-string]]
                   (fn [s]    
                     (when (re-matches re s)
                       result-string)))  
                 conditions)]
  ((apply some-fn preds) v))

2021-06-08T17:28:01.454400Z

this returns "Some bar"

2021-06-08T17:28:46.454600Z

perhaps it's better style to bind (apply some-fn preds) to a name in the let block

2021-06-08T17:32:55.454800Z

Thank you 🙂

2021-06-08T17:37:48.455100Z

thanks, appreciated

seancorfield 2021-06-08T17:38:19.455300Z

@kslvsunil If you’re willing to spend money on online courses, I highly recommend Eric Normand’s three courses on Property-Based Testing (beginner, intermediate, and advanced — if I recall correctly). On http://PurelyFunctional.tv

seancorfield 2021-06-08T17:39:45.455500Z

He walks you through several types of properties that you can look for in your problem space and also provides a lot of insight into how to build a “model” that you can use for comparing with your actual code, operating under property-based testing. They are excellent courses.

indy 2021-06-08T17:52:36.455800Z

That was a nice article, thanks Ghadi. Will check them out Sean, thank you.

mathpunk 2021-06-08T19:13:38.458100Z

i've been wondering why those seemingly redundant definitions exist for yeeeeeeears, this makes sense now

2021-06-08T19:41:54.461200Z

🍻

popeye 2021-06-08T19:43:11.462400Z

I am fetching the data from the database where data is coming like {:empiId 1256, :state Colombo} which is giving lazy seq on printing type, when I try to fetch the values it giving me castexception , initially I tried convert using (into {} output) later could not able to fetch the values of :state , can anyone help me please

2021-06-08T19:45:07.463300Z

the common problem when combining lazy seqs with databases is trying to realize the result after the connection has closed

2021-06-08T19:45:31.464200Z

> when I try to fetch the values in what way? what's the line of code and the error?

2021-06-08T19:45:49.464700Z

there are a lot of ways to get a ClassCastException

popeye 2021-06-08T20:12:35.464900Z

Hi @noisesmith, give me sometime i will try to regenerate the exception

2021-06-08T20:21:45.465100Z

looking at the code a second time: I think I like this reduce / reduced version beter

(let [conditions {#"^foo.*" "Some foo" #"^bar.*" "Some bar"}
      v          "bar-value-1"] 
  (reduce (fn [_ [re result-string]] 
               (when (re-matches re v)    
                 (reduced result-string)))   
          nil             
          conditions))
does the same thing, some might think it's less idiomatic I guess, I think it's significantly simpler, and it does less work

2021-06-08T20:51:56.465400Z

because it doesn’t need to create all those intermediate fns?

indy 2021-06-08T20:59:15.467700Z

I guess this peakfinder falls in the easy-to-prove bucket and so generative testing isn’t really required.

2021-06-08T22:38:20.468Z

or just use a parser that will parse alternatives and tell you which one matched

2021-06-08T22:43:58.468200Z

user=> (require '[instaparse.core :as insta])
nil
user=> ((insta/parser "thing=foo|bar\nfoo = 'foo'\nbar = 'bar'\n") "bar")
[:thing [:bar "bar"]]
user=> ((insta/parser "thing=foo|bar\nfoo = 'foo'\nbar = 'bar'\n") "foo")
[:thing [:foo "foo"]]
user=>

1👍