Ci-dessous est une implémentation très basique qui fait ce que vous cherchez. Il serait plus commune à eval la forme entière, mais puisque vous êtes désireux de simplement simplifier les expressions les plus intimes, ce le fait:
(defn leaf?
[x]
(and (list? x)
(symbol? (first x))
(not-any? list? (rest x))))
(defn eval-one
[expr]
(cond
(leaf? expr) (apply (-> (first expr) resolve var-get)
(rest expr))
(list? expr) (apply list (map eval-one expr))
:default expr
))
(read-string "(+ 1 (+ 2 (/ 6 3)))")
=> (+ 1 (+ 2 (/ 6 3)))
(eval-one *1)
=> (+ 1 (+ 2 2))
(eval-one *1)
=> (+ 1 4)
(eval-one *1)
=> 5
C'est naïf et à des fins d'illustration seulement, donc s'il vous plaît ne soyez pas sous l'impression qu'un vrai eval fonctionnerait de cette façon.
Nous définissons une feuille comme une liste dont le premier élément est un symbole et qui ne contient aucune autre liste qui pourrait être évaluée. Nous traitons ensuite le formulaire, évaluant les expressions feuilles, évaluant récursivement les expressions non-feuilles qui sont des listes, et pour toute autre chose, nous l'insérons simplement dans l'expression résultante. Le résultat est que toutes les expressions les plus profondes qui peuvent être évaluées, selon notre définition, sont évaluées.
Quel est mon cas de base? Comment puis-je déterminer que (/ 6 3) doit être évalué en premier? –
Votre scénario de référence est une expression numérique. '6' évalue à' 6'. Ainsi '(évaluer '(/ 6 3)); ==> ((get-fun '/) (évaluer' 6) (évaluer '3)) '. Vous n'avez pas besoin de le déterminer puisque l'évaluateur fera toujours ses dépendances en premier. – Sylwester