DSL в Clojure, который заменяет объектно-ориентированное программное решение? - PullRequest
5 голосов
/ 14 октября 2011

Привет, ребята: мне было интересно, кто-нибудь знал о конкретном примере DSL в Clojure, который заменяет абстракцию и удобочитаемость хорошей ОО-программы (написанной, скажем, на Java).

Я пытался превратить модель данных ОО (которая основана на "bean", с очень абстрактными методами, которые скрывают базовые реализации) в неопределенность ...

Я знаю, что существуют «макросы» и «функции более высокого порядка», однако я никогда не видел, чтобы они применялись к реальному набору данных, который легко понять (например, система регистрации курса или автосалон, или биллинговая система, или что-то в этом роде, вспомните печально известные примеры «JPetStore», которые Hibernate и Ibatis популяризировали в последнее десятилетие).

В любом случае ... Мой основной вопрос:

Существуют ли какие-либо доменные шаблоны для обучения моделированию реальных систем в Clojure с использованием протоколов и функций более высокого порядка?

Ответы [ 3 ]

3 голосов
/ 20 октября 2011

Специальных шаблонов для DSL не существует - вы просто берете инструменты, доступные на языке , и стараетесь сделать его максимально удобным и близким к домену . Лисп просто дает вам больше инструментов, чем другие языки.

Для конкретного примера хорошего DSL посмотрите ClojureQL . Изначально SQL создавался как DSL для реляционных баз данных. И это очень удобно для работы с консоли ... но не с языка программирования, такого как Java или Clojure. Java поставляется с большими платформами ORM, такими как Hibernate, а Clojure предлагает простой DSL, который так же удобен, как и оригинальный SQL, но полностью работает как часть языка:

(select (table :users) (where (= :id 5)))

Обычно в Lisp DSL используются такие конструкции, как defsomething. Например, в одной книге (извините, я не помню ее названия) есть пример сопоставления с образцом в тексте. Автор создает модуль с рядом соответствий, таких как ? для одного слова, + для одного или нескольких слов, * для нуля или более слов и так далее. Для этого он создает макрос defmatcher, который принимает некоторый синтаксис и добавляет обработчик для этого синтаксиса в центральный реестр. Это просто абстракция - вместо нескольких повторяющихся операций он вводит один макрос, рассказывающий о том, что он на самом деле хочет сделать - определить matcher. Также в этом примере используются как макросы, так и функции высокого порядка.

Итак, еще раз, в DSL на основе Lisp нет ничего особенного - вы просто описываете область домена с помощью инструментов на вашем языке , будь то Java, Clojure или что-то еще. Просто привыкните к языковым возможностям, и вы увидите, как это должно выглядеть.

UPD. Некоторые "реальные" примеры, когда DSL на основе Lisp более удобны, чем, скажем, ООП:

Домен: автосалон

(defcar my-cool-car :wheels 4, :doors 2, :color red) ;; in Java you need Factory
(def car1 (make-car my-cool-car))                    ;; and lots of methods to 
                                                     ;; add features to cars and 
                                                     ;; cars to factory

Домен: биллинговая система

(transaction                ;; in Java you cannot create wrapping constructs
  (withdraw account1 100)   ;; so you have to use inheritance, annotations, etc.
  (put account2 100))       ;; which is much more code

Домен: некоторый веб-сервис, который обрабатывает запросы нескольких типов

(defhandler :show-all (fn [params] ...))     ;; adds defined function to the
(defhandler :find-best (fn [params] ...))    ;; map of :message-type -> function
...
(defn handle [message]
   (let [msg-type (:type message), msg-params (:params message)]
     (if (contains? *handlers* msg-type) 
       ((*handlers* msg-type) msg-params)
       (throw (Exception. (concat "No handler for type" (:type message)))))))

В этих примерах нет ничего особенного - вы можете реализовать их все на Java или любом другом языке. Тем не менее, такие вещи, как ключевые слова (1-й пример), функции высшего порядка (2-й пример), макросы (все 3 примера) делают код более лаконичным и наглядным.

1 голос
/ 20 октября 2011

ООП хорош в том смысле, что мы действительно привыкли к нему, и оно сопоставляется с концепциями в реальном мире.

Вы можете увидеть, как построить систему ООП с картами и несколькими методами (что-то похожее на наследование прототипов в JS) в Joy of clojure, глава 9.

В книге Лиспа от Пола Грэма показано, как создать систему объектов в Лиспе. Должно быть легко приспособить его к clojure.

В этой книге также подробно объясняется программирование «снизу вверх», то есть построение небольших базовых блоков и их составление для построения конструкций более высокого уровня.

Кроме того, если вы видите, что основная концепция во многих приложениях (например, java pet store) является процедурной / функциональной и не использует концепцию объектов, такую ​​как обобщение или инкапсуляция.

Боб не имеет поведения. Данные без инкапсуляции имеют методы getter / setter, обеспечивающие публичный доступ к ним. Для этого вы можете использовать структуру C (на типизированном языке) или карту на динамическом языке, таком как clojure.

Служба, которая работает с ними, в основном является функциями. Они не имеют состояния и берут данные из параметров (бинов) или базы данных. Если вам действительно нужен интерфейс, у вас есть протоколы в ближайшем будущем.

Это не так сложно.

Назовите ваши бины как в JAVA ... Но используйте их на карте clojure или в виде записей

Назовите свои сервисы и внедрите их как функции.

Нужны фабрики? Это функции, которые принимают конфигурацию и возвращают функции.

Нужна инъекция зависимости? Ну, вы можете использовать параметры функции.

1 голос
/ 16 октября 2011

Я не знаю, ищите ли вы это, но я прочитал книгу о Clojure (программирование Clojure; прагматические программисты), в которой содержится пример симпатичного маленького DSL.Вы можете найти код в https://github.com/stuarthalloway/lancet. По сути, ланцет - это что-то вроде make или ant , но реализованный как Clojure-DSL.

...