2011-03-18 3 views
7

Я хотел бы запустить сеанс о Clojure. Не могли бы вы порекомендовать проблему, которая может быть элегантно решена с помощью функционального программирования с Clojure? Можете ли вы указать на ресурсы, которые охватывают эту тему?Что такое хорошая витрина для Clojure?

+0

Какая сессия? Вы ищете проблему и решение, которое можно объяснить через час, день, неделю? Есть много возможностей. –

+0

У нас есть регулярное мероприятие, посвященное компании, для демонстрации новых технологий. Он предназначен для 2-х рук на сеансе. – spa

ответ

12

Много аргументов для использования Clojure, как представляется, связано с его обработкой параллелизм, но я не буду касаться этого вопроса здесь.

Я расскажу о некоторых проблемах, с которыми я вынужден работать неделю, неделю с Java, и как я их решаю в Clojure.

Неизменность

В Java достижение неизменности очень и очень трудно. Помимо строгих правил кодирования, вам придется очень тщательно выбирать свои структуры и библиотеки. Кроме того, в качестве побочного эффекта вы либо напишите много кода, чтобы сделать чистый и полезный API, либо просто заставите клиента справиться с этим.

final Person person = personDao.getById(id); 
// I would like to "change" the person's email, but no setters... :(

В Clojure вы модель данных на основе неизменных структур данных, поэтому все объекты являются неизменяемыми по умолчанию, и из-за этого Clojure предлагает мощные функции, которые работают в этих структурах.

(let [person   (get-by-id person-dao id) 
     person-with-email (assoc person :email email)] 
    ; Use person-with-email... 

Конверсия

В Java у вас есть домен класс Person с полями id, name, email, socialSecurityNumber и другими. Вы создаете веб-службу для получения имен и писем всех лиц в вашей базе данных. Вы не хотите раскрывать свой домен, чтобы создать класс PersonDto, содержащий name и email. Это было легко, поэтому теперь вам нужна функция для сопоставления данных от Person до PersonDto. Возможно, что-то вроде этого:

public class PersonPopulator { 
    public PersonDto toPersonDto(Person person) { 
     return new PersonDto(person.getName(), person.getEmail()); 
    } 

    public List<PersonDto> toPersonDtos(List<Person> persons) { 
     List<PersonDto> personDtos = new ArrayList<PersonDto>(); 
     for (Person person : persons) { 
      personDtos.add(toPersonDto(person)); 
     } 
     return personDtos; 
    } 
} 

Хорошо известно, что не так уж плохо, но что, если вы хотите поместить больше данных в DTO? Ну код конструктора в toPersonDto будет расти немного, не стоит беспокоиться. Что делать, если есть два разных варианта использования: один, как указано выше, и другой, где мы хотим отправить только электронные письма? Ну, мы могли бы оставить name нулевой (плохая идея) или создать новый DTO, возможно PersonWithEmailDto. Таким образом, мы бы создали новый класс, несколько новых методов для заполнения данных ... вы, вероятно, видите, где это происходит?

Clojure, динамически типизированный язык с неизменяемыми структурами данных, позволяет мне сделать это:

(defn person-with-fields [person & fields] 
    (reduce #(assoc %1 %2 (get person %2)) {} fields)) 

(person-with-fields {:id 1 
        :name "John Doe" 
        :email "[email protected]" 
        :ssn "1234567890"} :name :email) 
; -> {:email "[email protected]", :name "John Doe"} 

И манипулировать список лиц:

(map #(person-with-fields % :name :email) persons) 

Кроме добавления специальных данных к человеку будет легко:

(assoc person :tweets tweets) 

И это ничего не сломает. В Java, если ваши объекты неизменяемы, у них, вероятно, нет сеттеров, поэтому вам нужно будет написать много шаблонов, чтобы изменить одно поле (new Person(oldPerson.getName(), oldPerson.getEmail(), tweets)) или создать совершенно новый класс. Объекты Mutable предлагают хороший API (oldPerson.setTweets(tweets)), но их трудно проверить и понять.

Тестирование

Много Java кода основана на некотором состоянии даже тогда, когда нет необходимости в этом. Это означает, что вы можете либо издеваться над этим состоянием, что обычно означает дополнительный шаблон и становится сложнее, если вы не создали свой код с возможностью проверки. С другой стороны, тесты без издевательств, как правило, медленны и зависят от доступа к базе данных или времени или чего-то еще, что будет время от времени терпеть неудачу.

При кодировании Clojure я заметил, что на самом деле мне не нужно столько состояния. Практически единственные ситуации, когда я извлекаю что-то из «снаружи», будь то база данных или какой-либо веб-сервис.

Резюме

Мой код трубы, с одной стороны я получаю некоторые данные, затем эти данные изменены в трубе с помощью фильтрации, преобразования или присоединения к нему с некоторыми другими данными, пока он не достигнет конца труба. Внутри трубы нет необходимости действительно изменять данные, но во многих случаях полезны мощные функции и неизменные структуры данных, поэтому Clojure работает с таким кодом.

+0

Ничего себе, отличный пример. – defhlt

+0

Мне понравилось резюме. Именно так я чувствовал себя во время работы с Clojure в течение трех месяцев. –

1

Пару месяцев назад я столкнулся с той же проблемой, и мы решили решить проблему «Моны Лизы» в Клоджуре. В результате получилось this presentation. В основном мы показали, что Clojure чрезвычайно крут для решения проблем, для которых «код как данные» дает элегантное решение. Например, в генетических алгоритмах.

Смежные вопросы