Search code examples
clojure

create new variables in a long function in clojure


So I recently learned that I cannot modify parameters in a Clojure function. I have a big function that takes in a list, then does about 5 different steps to modify it and then returns the output.

But what I'm doing now is

(defn modify [my-list other params]
  (if (nil? my-list)
      my-list
      (let [running my-list]
       (def running (filter #(> (count %) 1) my-list)) 
       (def running (adjust-values running))
   ; a whole bunch of other code with conditions that depend on other parameters and that modify the running list
       (if (< (count other) (count my-list))
           (def running (something))
           (def running (somethingelse)))
       (def my-map (convert-list-to-map my-list))
       (loop [] .... ) loop through map to do some operation
       (def my-list (convert-map-to-list my-map)
     running
)))

This doesn't seem correct, but I basically tried writing the code as I'd do in Python cuz I wasn't sure how else to do it. How is it done in Clojure?


Solution

  • Yes, this is the way Clojure was designed: as a functional language with immutable data (of course with fallbacks to what the host offers if you want or need it).

    So if you want to modify data in consecutive steps, then you can either chain the calls (looks nicer with the threading macros). E.g.

    (->> my-list 
         (filter #(> (count %) 1)) 
         (adjust-values))
    

    This is the same as:

    (adjust-values 
      (filter #(> (count %) 1) 
              my-list))
    

    If you prefer to do that in steps (e.g. you want to print intermediate results or you need them), you can have multiple bindings in the let. E.g.

    (let [running my-list
          filttered (filter #(> (count %) 1) running)
          adjusted (adjust-values filtered)
          running ((if (< (count other) (count adjusted)) something somethingelse))
          my-map (convert-list-to-map my-list)
          transformed-map (loop [] .... )
          result (convert-map-to-list transformed-map)]
      result)
    

    This returns the adjusted values and holds on to all the things in between (this does nothing right now with the intermediate results, just an example).

    And aside: never ever def inside other forms unless you know what you are doing; def define top level vars in a namespace - it's not a way to define mutable variables you can bang on iteratively like you might be used to from other languages).