Портирование фрагмента кода Lisp на Clojure (PAIP)

Я читаю парадигмы программирования искусственного интеллекта (PAIP) Питера Норвига, и я пытаюсь написать весь код в Clojure, а не обычный Lisp. Однако я застрял на этом фрагменте кода на стр. 39:

(defparameter *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 *grammar* *simple-grammar*)

Как я могу перевести это в Clojure? Спасибо.

Ответ 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 (исходный код).

Эти изменения позволят вам использовать больше встроенной мощности языка вместо того, чтобы, например, писать небольшие вспомогательные функции для управления вложенными списками.

Ответ 2

Кен прав, всего лишь несколько изменений в формах def * и другой стиль docstring (docstrings немного проще для определения функций, чем для обычных vars):

(def ^{:doc "A grammar for a trivial subset of English."} 
  *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)))

(def *grammar* *simple-grammar*)