 
   "
   [term & {:as env}]
-  (ev term env))
+  (ev term #{} env))
 
 (defn ?
   "funcall, the counit of product-exponential adjunction"
   ([& terms]
-   (as-> (ev (Beta. terms) {}) term
-     (if (beta? term)
-       (ev (Form. term (apply clojure.set/union (map fv terms))) {})
-       term)))
+   (let [terms (for [t terms] (if (var? t) (Form. t #{t}) t))
+         vars (apply clojure.set/union (map :vars (filter form? terms)))]
+     (ev (Beta. terms) vars {})))
   ([]))
 
 (defn %
   "forall"
   ([term & args] ; currently args can only be vars
-   (-> (Forall. term (vec args))
-       (ev {})
-       (Form. (reduce disj (if (form? term) (:vars term) #{}) args))
-       (ev {})))
+   (ev (Forall. term (vec args))
+       (reduce disj (if (form? term) (:vars term) #{}) args)
+       {}))
   ([term] term))
 
 (defn !

  )

;; todo
;; - test how to replace var using env

;; vars = set var
;; args = vec var

;; term =  val | form
;; form = expr & vars
;; expr =  var | beta | forall
;;
;; expr must be wrapped in form, otherwise it is treated as val
;; binding a var to a form changes everything
;;
;; val    => val
;; var    => val | form *
;; form   => val | form
;; beta   => val | form *
;; forall => form forall

(defrecord Form   [expr vars])    (defn form?   [x] (instance?  Form   x))
(defrecord Var    [name])         (defn var?    [x] (instance?  Var    x))
(defrecord Beta   [sexp])         (defn beta?   [x] (instance?  Beta   x))
(defrecord Forall [term args])    (defn forall? [x] (instance?  Forall x))
(defprotocol Expr)                (defn expr?   [x] (satisfies? Expr   x))
(extend-protocol Expr Var Beta Forall)

(defprotocol Term
  "

  ev

  - substitutes all keys in expr to vals in env (: map var val)
  - beta reduces a term whose expr has a Forall as head

  "
  (ev [this vars env]))

(extend-protocol Term

  Form
  ;; - val if its content reduces to val
  ;; - form * with newly collected free vars
  ;; todo guard from ev
  (ev [{:keys [expr vars]} vars env]
    (ev expr (reduce disj vars (keys env)) env))

  Var
  ;; - val
  ;; - form *
  (ev [this _ env] (env this this))

  Beta
  ;; - val
  ;; - form *
  (ev [{sexp :sexp} vars env]
    (let [;; evalutes sexp if necessary
          ;; env (select-keys env vars)
          [head & body :as sexp] (cond->> sexp (seq env) (map #(ev % vars env)))
          vars (reduce disj vars (keys env))]
      (if (and (form? head) (forall? (:expr head)))
        (let [{:keys [expr vars]} head
              {:keys [term args]} expr
