Ответ 1
Я относительный Clojure новичок, который прошел через это точное упражнение некоторое время назад. Здесь нужно подумать о том, хотите ли вы как можно ближе придерживаться кода Норвига (например, писать "Common- Lisp -favored" Clojure) или если вы хотите написать что-то ближе к идиоматическому Clojure, Вот что я сделал:
(use '[clojure.contrib.def :only [defvar]])
(defvar *simple-grammar*
{:sentence [[:noun-phrase :verb-phrase]]
:noun-phrase [[:Article :Noun]]
:verb-phrase [[:Verb :noun-phrase]]
:Article ["the" "a"]
:Noun ["man" "ball" "woman" "table"]
:Verb ["hit" "took" "saw" "liked"]}
"A grammar for a trivial subset of English.")
defvar - это сахар, который позволяет вам естественным образом добавлять докстерии к vars. В этом случае я использую карту (пары значений ключа, разделенные символом {}), чтобы получить поиск в стиле словаря из LHS каждого правила в RHS. Я также использую векторы (ограниченные []) вместо списков для представления RHS каждого правила. Вообще говоря, "идиоматический" Clojure код редко использует списки для хранения последовательных данных; векторы предпочтительны, если вы не представляете формы Clojure (исходный код).
Эти изменения позволят вам использовать больше встроенной мощности языка вместо того, чтобы, например, писать небольшие вспомогательные функции для управления вложенными списками.