Search code examples
recursionclojure

Working with nested input, but not flattening it


I have a function that will simplify something like:

(or x false) => x

Then function definition takes in the unevaluated expression as its parameter. I am trying to nest my input like this now:

(or x (and true))

Everywhere I look I see articles about flattening nested input, but that won't work in this case because of the logical operator at the beginning of each list so the innermost list must be processed first, with the result being sent to the next outer list as an argument.

I know I need to call my function within it's own body with the result of the innermost list until I reach the outermost list, but I'm not sure of the way to go about that or what to research in Clojure on how to to this.


Solution

  • What you are describing is nearly exactly the semantics of expression evaluation in clojure :-) so the brief answer would be to run the code :-D though i suspect you are looking for a more interesting answer.

    Here is a simple recursive version that works by

    1. recursively simplify each nested expression
    2. apply the simplification rules to the existing expression

    This uses an overly-simple rule just as an example:

    user> (defn my-eval [e]      
            (let [expanded-form (if (seq? e)
                                  (map (fn [i]          
                                         (if (seq? i)    ;; if this is a sequence, 
                                           (my-eval i) ;; eval the sequence and include the result here
                                           i))         ;; otherwise use the value unchanged.
                                       e)
                                  e)] ;; if it's not a seq with something in it, leve it unchanged
              (if (and
                   (seq? expanded-form)
                   (= (first expanded-form) 'or)
                   (= 2 (count (remove false? expanded-form))))
                (second (remove false? expanded-form))
                expanded-form)))
    #'user/my-eval
    

    First a base case test:

    user> (my-eval '(or x (or y false)))
    (or x y)
    

    Then with a little recursion:

    user> (my-eval '(or (or x false) (or y false)))
    (or x y)