Fork me on GitHub
Little Mose00:11:08

Hi, any suggestion of open source project for a beginner with some entry level Clojure learner to start?

👍 2

Are you looking for a public project to contribute to, or are you generally looking to code more Clojure to improve your skills? If the latter, I would recommend 4clojure and Advent of Code.


Not sure about those to be honest. They work for some people but others (myself included) aren't into solving arbitrary puzzles. They can be challenging but I think they're too detached from real-life applications. If you ask me, real-world projects are usually more meaningful if they solve real-world problems, so I'd start from that. What's a problem in your life that you'd like to solve? This is great because part of the design process is to read other people's code and you're less likely to lose interest in it because, once it's finished, you'll be getting some value out of it. Games are a fun choice as well and they make you think about state in Clojure, e.g. tic-tac-toe is a popular first project.


Oh and in the beginning try to avoid projects that have a lot of moving parts, e.g. an eshop is not a good first project imo. On the other hand, working with public datasets is simple and can be a lot of fun. Interact with one of the countless public APIs out there and do stuff with their data.

Little Mose01:11:07

Thanks for reply! Very helpful. Yes, I was addicted to programming contest, but after many years of programming, I don't have the time and desire for puzzle-style problem. I spent some time in to get the sense of programming in Clojure, and then I would like to find the differences between Clojure and other languages in real projects.

Little Mose01:11:49

Currently, I'm trying to implement a rss-reader client, which I have implemented in other languags, I think it's a nice start point.


what is the closest to "`condlet` " ? I'm looking for a mix of cond and when-let . Like

 [thing (re-find ...)] (do-stuff1 thing)
 [other-thing (re-find ...)] (other ...)

Ben Sless10:11:42

What's exactly the expected behavior?

Ben Sless10:11:37

Seems like you can roll your own with if-let


don't I have to nest if-let then?


You can use a custom macro to do the nesting for you.


lulling to the docstring. Did Rich mention that he doesn't like this one once what?


yeah first time I noticed the comment tbh; but probably it's a complexity thing 😛

👍 1
Ben Sless10:11:24

Just don't mix the two, keep cond-let just a series of nested if-lets


seems to work

(defmacro condlet
  "Try to bind each binding form via if-let.
  Evaluate the first form with the binding-form bound.
  Else evaluate to the last dangling form, nil if ommitted. "
  [& forms]
  (when forms
    (let [[binding form & more-forms] forms]
      (if (and binding form)
             ~binding ~form
             (condlet ~@more-forms))
tried better doc string

Ben Sless12:11:29

This is good, and simpler than the sugar-ed version


(defmacro <<- [& forms]
  `(->> ~@(reverse forms)))

  (if-some [thing (re-find ...)] (do-stuff1 thing))
  (if-some [other-thing (re-find ...)] (other ...))
<<- brought to you by this tweet: @U02CV2P4J6S

clojure-spin 1
Muhammad Hamza Chippa14:11:02

how i can compare the value of vector with its previous values for example if I have vector [5 6 4 8] how can I compare the 6 with 5 , 7 with 6 I wanted something like this if value is greater than previous value return red otherwise green like [green green red green] ?


 [5 6 4 8] 
 (partition 2 1)
 (map #(apply < %))
 (map #(if % :green :red)))


Maybe this will help you?

(partition 2 1 [5 6 4 8])
=> ((5 6) (6 4) (4 8))


Hi, lets say that i get a max values like this

  (fn [lst] (apply max-key :price lst)) 
  (partition 5  
    [{:name 1 :price 10} 
     {:name 2 :price 10} 
     {:name 3 :price 20} 
     {:name 4 :price 50} 
     {:name 5 :price 40} 
     {:name 6 :price 70} 
     {:name 7 :price 15} 
     {:name 8 :price 20} 
     {:name 9 :price 14} 
     {:name 10 :price 24}])))
and the result is
({:name 4, :price 50} {:name 6, :price 70})
I would like to learn what is the nice & idiomatic way to distribute this result to the original maps like this fe:
({:name 1 :price 10 :max 50} {:name 2 :price 10 :max 50} {:name 3 :price 20 :max 50} {:name 4 :price 50 :max 50} {:name 5 :price 40 :max 50}
{:name 6 :price 50 :max 70}  {:name 7 :price 15 :max 70} {:name 8 :price 20 :max 70} {:name 9 :price 14 :max 70} {:name 10 :price 24 :max 70}


(->> [{:name 1 :price 10} 
        {:name 2 :price 10} 
        {:name 3 :price 20} 
        {:name 4 :price 50} 
        {:name 5 :price 40} 
        {:name 6 :price 70} 
        {:name 7 :price 15} 
        {:name 8 :price 20} 
        {:name 9 :price 14} 
        {:name 10 :price 24}]
       (partition 5)
       (map (juxt (fn [lst] (apply max (map :price lst))) identity))
       (mapcat (fn [[mx lst]] (map #(assoc % :max mx) lst))))
maybe something like that???

👍 1

This is nice


In this case, I would take a step back and ask “Is there a way to structure the output data so I don’t have to distribute the result to every map?”


My first thought is something like this @zikajk

dev=> (into [] 
 #_=>       (comp (partition-all 5)
 #_=>             (mapcat #(let [max-price (:price (apply max-key :price %))]
 #_=>                        (map merge % (repeat {:max max-price}))))) 
 #_=>       data)
[{:name 1, :price 10, :max 50} {:name 2, :price 10, :max 50} {:name 3, :price 20, :max 50} {:name 4, :price 50, :max 50} {:name 5, :price 40, :max 50} {:name 6, :price 70, :max 70} {:name 7, :price 15, :max 70} {:name 8, :price 20, :max 70} {:name 9, :price 14, :max 70} {:name 10, :price 24, :max 70}]


Thanks, i wrote something similar. So i believe this is a not so bad solution coming from you :-)


But I hope someone will suggest something nicer for that nested max/map expression...

👍 1

How often would you say with-precision is really the answer to Non-terminating decimal expansion; no exact representable decimal result. ? I'm wondering whether the exception is just a symptom of bad design sometimes. Edit: "bad design" as in mixing bigdecimals and doubles when you only need doubles, or something. Sorry if the question doesn't make a lot of sense, I don't understand the issue very well but I've started seeing it more often lately (in code that didn't use to need the with-precision workaround) and that made me wonder.


What's wrong with ratios?


Depends on the domain too. When modeling money, for instance, generally you want to stay in bigdecimal land


and in that situation you can have operations where you can't guarantee exact decimal representations. Exchange rates, for instance.

👍 1

> What's wrong with ratios? How do you mean that?


(/ 2 3)
;; => 2/3

(/ 2.0 3.0)
;; => 0.6666666666666666
I guess if you’re passing in floating point numbers you’ll get more out, but integers can be turned into ratios so there’s no need to deal with floating point precision in such cases.


Ratios are exact for + - * /, but note that the memory required to maintain that exactness can grow linearly over a sequence of N dependent math operations, if the denominators are different enough.


e.g. do not have small lowest-common-denominators with the intermediate numerator values.


And thus the run time for doing those exact + - * / operations can also grow at least linearly, or more, for many dependent math ops.


BigDecimal does not have these issues, because while it is exact for + - operations, it is NOT exact for all * / operations -- you must specify for each such operation how it will do rounding or truncation.

Noah Bogart19:11:34

is there a way to tell if a swap! changed the atom?

Alex Miller (Clojure team)19:11:07

use swap-vals! instead - compare the old/new that are returned

👍 1
🎯 1
Noah Bogart19:11:00

forgot about that one, thanks!


or compare-and-set!


A little specific, but something weird happened and I don't understand.. I've been working with for a few days, interacting with it from my REPL and such. All good. Suddenly I've started getting very heavy log output like this when making calls to it:

2021-11-19T20:14:05.103Z x DEBUG [] - file=/home/sheluchin/repos/foo/.git/config, create new FileSnapshot: lastRead=2021-11-19 15:14:05.099201000, lastModified=2021-11-18 14:52:20.617262000, size=92, fileKey=(dev=3c,ino=3903529)
2021-11-19T20:14:05.120Z x DEBUG [] - file=null, size changed from -1 to 124 bytes
2021-11-19T20:14:05.125Z x DEBUG [org.eclipse.jgit.util.SystemReader:389] - loading config FileBasedConfig[/home/sheluchin/.config/jgit/config]
I know it's a bit specific, but is there something I should check for? My repo doesn't seem to have any related changes.


Very likely you don't have any logging setup in your project, so the log output you get is at the whims of whatever logging setup your dependencies bring in


Which can be a tangle, likely you added a new dependency (not logging related) that did this


If you don't proactively setup logging then things like the order of different dependencies in the classpath can alter logging behavior


I don't think so. I didn't add any new deps lately and my project is based on the fulcro-rad-demo, so it has this: Do I need some specific subkeys here maybe? Still not sure why it suddenly started happening though :thinking_face:


It isn't going to be any of that


What your are seeing is the default output from an unconfigured java.util.logging


And timbre is a whole other thing


Oh, so I should look at how to set up config for java.util.logging?


That would be one way


My preference for complex projects these days is to setup up log4j2 and redirect all the other java logging to it


If you haven't encountered the complexities of java logging before, you can sort of split logging into a top half and bottom half. The top half is the API that programs call with log messages, the bottom half actually outputs the log messages somewhere.


A lot of logging libraries provide both a top and bottom half, and some libraries, like the clojure specific tools.logging is just the top half


And most logging libraries provide shims that act like the top half of other libraries, but direct messages to their own bottom half


Timbre is this weird kind of attempt to paper over the complexities of logging, while also doing some clojure specific stuff, and I don't really care for it, and avoid using it, so I can't speak too much to how it is effecting all of that


The logging stuff there appears to be trying to pipe the top half of a lot of java logging libraries to the log4j bottom half


My mistake, it is piping it to slf4j bottom half


Mmm, that output may not actually be from java.util.logging, but from slf4j, so configuring slf4j, possibly through timbre may be the thing


Heh, this sounds like a job I shouldn't be doing last thing on a Friday 🙂


Thanks @hiredman, that gives me a lot to look into. I'll leave it to the next morning to tackle this. A little odd that is just randomly started happening, but there must have been some event in my workflow that triggered the change and I just don't remember.


Ah, figured it out. Totally my fault. The function which starts the HTTP server and populates the DB also inits the config, and I wrongly assumed since I was only interacting with git/local filesystem, I didn't need any of that... on this particular run. I attribute it to fatigue 😛 But I appreciate your explanation very much nonetheless. I'm not that familiar with java logging complexities, so this top/bottom split gives me something to look into before I inevitably do encounter it.