 (ert-deftest simplify--known-fn-call ()
   "If we know we're calling a function, we should simplify its
 arguments."
+  ;; Function with side effects.
   (should
    (equal
     (whatif--simplify '(message x) '((x . 1)))
-    (list 'partial '(message 1)))))
-
-(ert-deftest simplify--partial-fn-call ()
+    (list 'partial '(message 1))))
+  (should
+   (equal
+    (whatif--simplify '(+ x 2) '((x . 3)))
+    (list 'value 5))))
+
+(ert-deftest simplify--unknown-fn-call ()
   "If we don't recognise the symbol, do nothing."
   (should
    (equal

      (`(value ,value)
       (push (list 'value value) simplified-exprs)))
    (nreverse simplified-exprs)))

(defun whatif--simplify (form bindings)
  "Simplify FORM in the context of BINDINGS using partial application.

           (`() (list 'value nil))
           (`(,expr) (list 'partial expr))
           (`,exprs (list 'partial `(or ,@exprs)))))))

    ;; Function call.
    ((and `(,fn . ,args) (guard (functionp fn)))
     (message "raw args: %s" args)
     (setq args (--map (whatif--simplify it bindings) args))
     ;; If it's a pure function, and we could evaluate all the
     ;; arguments, call it.
     (if (and
          (whatif--values-p args)
          (get fn 'side-effect-free))
         (progn
           (message "args: %s" (mapcar #'cl-second args))
           (list 'value (apply fn (mapcar #'cl-second args))))
       (list 'partial `(,fn ,@(mapcar #'cl-second args)))))
    (`(,fn . ,args)
     ;; Either a function we don't know about, or a macro. We can't
     ;; simplify because we don't know which arguments are evaluated.
     (list 'partial form))

    (_ (error "Don't know how to simplify: %s" form))))

(ert-deftest simplify--bool ()
