funcool

carlos hernandez 2025-02-26T18:03:00.207529Z

Hey! I'm using nubank/state-flow which heavily relies on funcool/cats monads, and compiling code that gets written to disk is for most purposes not possible because the resulting class names of heavily nested anonymous functions would surpass the OS limit. A different approach for implementing the mlet macro would create small enough class names. Details of my proposal in the thread 🧵

carlos hernandez 2025-02-26T18:03:07.068989Z

(m/mlet [a (maybe/just 1)
         b (m/return (inc a))
         c (m/return (inc b))]
         (m/return (* c 2)))
Currently the result of the macro expansion of the call above looks like this:
(cats.core/bind
      (maybe/just 1)
      (clojure.core/fn
        [a]
        (cats.core/bind
          (m/return (inc a))
          (clojure.core/fn [b] (cats.core/bind (m/return (inc b)) (clojure.core/fn [c] (do (m/return (* c 2)))))))))
The more bindings we add the more nested functions are created. having bindings from a to s gives the following resulting names when writing the compiled classes to disk:
my_dear_test$monad_test_nested_mlet
my_dear_test$monad_test_nested_mlet$fn__174484
my_dear_test$monad_test_nested_mlet$fn__174484$fn__174485
my_dear_test$monad_test_nested_mlet$fn__174484$fn__174485$fn__174486
my_dear_test$monad_test_nested_mlet$fn__174484$fn__174485$fn__174486$fn__174487
my_dear_test$monad_test_nested_mlet$fn__174484$fn__174485$fn__174486$fn__174487$fn__174488
my_dear_test$monad_test_nested_mlet$fn__174484$fn__174485$fn__174486$fn__174487$fn__174488$fn__174489
my_dear_test$monad_test_nested_mlet$fn__174484$fn__174485$fn__174486$fn__174487$fn__174488$fn__174489$fn__174490
my_dear_test$monad_test_nested_mlet$fn__174484$fn__174485$fn__174486$fn__174487$fn__174488$fn__174489$fn__174490$fn__174491
my_dear_test$monad_test_nested_mlet$fn__174484$fn__174485$fn__174486$fn__174487$fn__174488$fn__174489$fn__174490$fn__174491$fn__174492
my_dear_test$monad_test_nested_mlet$fn__174484$fn__174485$fn__174486$fn__174487$fn__174488$fn__174489$fn__174490$fn__174491$fn__174492$fn__174493
my_dear_test$monad_test_nested_mlet$fn__174484$fn__174485$fn__174486$fn__174487$fn__174488$fn__174489$fn__174490$fn__174491$fn__174492$fn__174493$fn__174494
my_dear_test$monad_test_nested_mlet$fn__174484$fn__174485$fn__174486$fn__174487$fn__174488$fn__174489$fn__174490$fn__174491$fn__174492$fn__174493$fn__174494$fn__174495
my_dear_test$monad_test_nested_mlet$fn__174484$fn__174485$fn__174486$fn__174487$fn__174488$fn__174489$fn__174490$fn__174491$fn__174492$fn__174493$fn__174494$fn__174495$fn__174496
my_dear_test$monad_test_nested_mlet$fn__174484$fn__174485$fn__174486$fn__174487$fn__174488$fn__174489$fn__174490$fn__174491$fn__174492$fn__174493$fn__174494$fn__174495$fn__174496$fn__174497
my_dear_test$monad_test_nested_mlet$fn__174484$fn__174485$fn__174486$fn__174487$fn__174488$fn__174489$fn__174490$fn__174491$fn__174492$fn__174493$fn__174494$fn__174495$fn__174496$fn__174497$fn__174498
my_dear_test$monad_test_nested_mlet$fn__174484$fn__174485$fn__174486$fn__174487$fn__174488$fn__174489$fn__174490$fn__174491$fn__174492$fn__174493$fn__174494$fn__174495$fn__174496$fn__174497$fn__174498$fn__174499
my_dear_test$monad_test_nested_mlet$fn__174484$fn__174485$fn__174486$fn__174487$fn__174488$fn__174489$fn__174490$fn__174491$fn__174492$fn__174493$fn__174494$fn__174495$fn__174496$fn__174497$fn__174498$fn__174499$fn__174500
my_dear_test$monad_test_nested_mlet$fn__174484$fn__174485$fn__174486$fn__174487$fn__174488$fn__174489$fn__174490$fn__174491$fn__174492$fn__174493$fn__174494$fn__174495$fn__174496$fn__174497$fn__174498$fn__174499$fn__174500$fn__174501
my_dear_test$monad_test_nested_mlet$fn__174484$fn__174485$fn__174486$fn__174487$fn__174488$fn__174489$fn__174490$fn__174491$fn__174492$fn__174493$fn__174494$fn__174495$fn__174496$fn__174497$fn__174498$fn__174499$fn__174500$fn__174501$fn__174502

carlos hernandez 2025-02-26T18:03:23.035979Z

By having the result of the macro expansion be something like this:

(let*
 [G__174687
  (clojure.core/fn [& [a b c]] (m/return (* c 2)))
  G__174686
  (clojure.core/fn [& [a b]] (cats.core/bind (m/return (inc b)) (clojure.core/partial G__174687 a b)))
  G__174685
  (clojure.core/fn [& [a]] (cats.core/bind (m/return (inc a)) (clojure.core/partial G__174686 a)))]
 (cats.core/bind (maybe/just 1) (clojure.core/partial G__174685)))
The resulting class names for the mlet with bindings from a to s are the following:
my_dear_test$monad_test_listed_mlet
  my_dear_test$monad_test_listed_mlet$G__174523__174665
  my_dear_test$monad_test_listed_mlet$G__174524__174659
  my_dear_test$monad_test_listed_mlet$G__174525__174653
  my_dear_test$monad_test_listed_mlet$G__174526__174647
  my_dear_test$monad_test_listed_mlet$G__174527__174641
  my_dear_test$monad_test_listed_mlet$G__174528__174635
  my_dear_test$monad_test_listed_mlet$G__174529__174629
  my_dear_test$monad_test_listed_mlet$G__174530__174623
  my_dear_test$monad_test_listed_mlet$G__174531__174617
  my_dear_test$monad_test_listed_mlet$G__174532__174611
  my_dear_test$monad_test_listed_mlet$G__174533__174605
  my_dear_test$monad_test_listed_mlet$G__174534__174599
  my_dear_test$monad_test_listed_mlet$G__174535__174593
  my_dear_test$monad_test_listed_mlet$G__174536__174587
  my_dear_test$monad_test_listed_mlet$G__174537__174581
  my_dear_test$monad_test_listed_mlet$G__174538__174575
  my_dear_test$monad_test_listed_mlet$G__174539__174569
  my_dear_test$monad_test_listed_mlet$G__174540__174563
  my_dear_test$monad_test_listed_mlet$G__174541__174557
  my_dear_test$monad_test_listed_mlet$G__174542__174551
  my_dear_test$monad_test_listed_mlet$G__174543__174545

carlos hernandez 2025-02-26T18:04:50.913509Z

WDYT?

carlos hernandez 2025-02-26T20:58:11.832899Z

As a reference, here's the mlet with bindings from a to s:

(defn monad-test-nested-mlet
  []
  (m/mlet [a (maybe/just 1)
         b (maybe/just (inc a))
         c (maybe/just (inc b))
         d (maybe/just (inc c))
         e (maybe/just (inc d))
         f (maybe/just (inc e))
         g (maybe/just (inc f))
         h (maybe/just (inc g))
         i (maybe/just (inc h))
         j (maybe/just (inc i))
         k (maybe/just (inc j))
         l (maybe/just (inc k))
         m (maybe/just (inc l))
         n (maybe/just (inc m))
         o (maybe/just (inc n))
         p (maybe/just (inc o))
         q (maybe/just (inc p))
         r (maybe/just (inc q))
         s (maybe/just (inc r))]
          (m/return (* s 2))))