Fork me on GitHub
#off-topic
<
2023-02-06
>
Jacob Rosenzweig01:02:10

Anyone mind trying out my social media site? I'm half way through a redesign but it should be pretty intuitive to use. https://conj.app

Jacob Rosenzweig01:02:07

You'll need a Google account for oauth. 😄

souenzzo15:02:09

Cant post from mobile. When I click on checkbox it does not select My mobile keyboard doesn't appear when I click on textareas

Martynas Maciulevičius19:02:03

I'm making my own small chunk of code (not sure if I can call it a library) and I think about having a lazy-evaluated let. For instance what if I could have this let:

(lazy-let [one-in-9k (rand-int 9000)
           my-sum (+ one-in-9k 123)
           my-sum2 (inc one-in-9k)
           my-database-fetch (* (fetch-db! db) my-sum2)
           my-sum3 (- my-sum my-sum2)]
  (println my-sum3))
So if I'd have only one of those three statements then not all of the let bindings actually need to run. And in this example the my-database-fetch would not be fetched. What do you think about this kind of let?

dgb2319:02:36

Cool/clever idea. But I'm trying to think of situations where I would want this though. I typically need the things I bind in a let or I comment them out.

borkdude20:02:51

I think plumatic also had this kind of let, where the order of bindings also didn't matter, the dependencies were calculated between them

2
borkdude20:02:31

Never used that though. clj-kondo reports unused bindings, so it's easy to get rid of them

☝️ 2
Noah Bogart20:02:33

Our usage is slightly different, however. We have a list of predefined bindings, and then step through the req (lazy let) call, find all "free locals" (local vars without existing definitions), then insert into the let block the predefined bindings that match.

Noah Bogart20:02:06

yours would be slightly different. instead of removing locals that contain a period (meaning it has a namespace), you'd want to gather all of the local, and then check the difference to see which let-bindings aren't used and remove those from the let

Martynas Maciulevičius20:02:32

I've already implemented a basic version and it works basically as an evaluator that walks through the binding map and caches the values as they're evaluated. This isn't efficient as it walks through the map on every execution but I wanted a simple POC. Later I could make it to remove the actual bindings to speed it up and prebuild the function/form in advance :thinking_face: Edit: Actually it doesn't use local variable scope because it simply does the dependency check for now. But if I'll use it then I'll do a proper implementation :thinking_face:

👍 4
p-himik21:02:09

> I think plumatic also had this kind of let Probably this? https://github.com/plumatic/plumbing#graph-the-functional-swiss-army-knife

borkdude22:02:46

yes. and letk

borkdude22:02:20

it might not be about unused things though

dgb2322:02:42

Couldn't you first parse the binding form to look for dependencies, then the body for the same reason and generate a let that omits the unused bindings with the same body?

dgb2322:02:36

I guess I meant to say "walk" instead of "parse"

dpsutton22:02:07

could you wrap each binding form in a delay, and each binding use in a deref and get this cheaply?

dpsutton22:02:06

usual semantics of lets that they have to be ordered sensibly, but on evaluation the delay derefs will take care of the calculation and only calculate what you need?

👍 2
dpsutton22:02:55

(defmacro lazy-let [bindings & body]
    (let [bound-syms (map first (partition 2 bindings))
          var->deref (zipmap bound-syms
                             (map (fn [x] (list 'deref x))
                                  bound-syms))
          replace    (partial clojure.walk/postwalk-replace var->deref)]
      `(let [~@(interleave bound-syms (map (comp (fn [x] (list 'delay x)) replace)
                                           (map second (partition 2 bindings))))]
         ~@(replace body))))

dpsutton22:02:09

cache=> (macroexpand '(lazy-let [x 1
                                 y (+ x 2)
                                 users (db/select 'Users)
                                 ids   (map :id users)]
                                (+ x y)))
(let*
 [x
  (delay 1)
  y
  (delay (+ (deref x) 2))
  users
  (delay (db/select (quote Users)))
  ids
  (delay (map :id (deref users)))]
 (+ (deref x) (deref y)))

clapping 2
phill22:02:52

@U01EFUL1A8M there is an example of such a walk in ztellman's manifold, to implement "let-flow"

🙏 2
phill22:02:16

IIRC in Manifold it got pretty complicated.

dpsutton22:02:04

good point. i remember that macro but don't remember why it gets harder.

borkdude22:02:28

user=> (lazy-let [x '[x y z]] x)
[(deref x) y z]

borkdude22:02:10

user=> (lazy-let [x (fn [x] x)] (x 1))
Syntax error macroexpanding clojure.core/fn at (REPL:1:1).

dpsutton22:02:17

oh right. he'll do the analysis to actually track usages of vars rather than just on symbol

dpsutton22:02:35

riddley to the rescue

borkdude22:02:47

I think you could maybe leverage &env somehow to make it more accurate, but maybe it's best to not use this macro at all and avoid this complexity ;)

Noah Bogart22:02:00

lol the code i posted handles this, but it requires jvm analyzer

respatialized21:02:08

http://www.rntz.net/datafun/ Datafun seems to blur the line between Datalog and general purpose programming language in a really interesting way.

👀 2
eggsyntax21:02:32

> Datafun's superpower is that it can concisely and declaratively express and compute fixed points of monotone maps on semilattices. Ah yes, and a monad is just a monoid in the category of endofunctors 😏

eggsyntax22:02:01

But snark aside, the Strange Loop talk is very accessible 🙂 https://www.youtube.com/watch?v=gC295d3V9gE

mauricio.szabo00:02:49

Amazing how I understood NOTHING about what the language is 😱

eggsyntax01:02:24

I didn't watch to the end of the talk, but I came away with an understanding of 'Idris plus first class sets and set comprehensions' as at least an equivalent, with a bunch of work at the implementation level to make that fast and (I assume) agnostic to whether a given set exists in memory or in a database.