什么是Clojure的好展示?

时间:2011-03-18 14:50:52

标签: clojure

我想开一个关于Clojure的会议。你能推荐一个可以通过Clojure函数编程优雅解决的问题吗?你能指出涵盖这个主题的资源吗?

3 个答案:

答案 0 :(得分: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,其中包含字段idnameemailsocialSecurityNumber和其他字段。您正在创建一个Web服务,用于检索数据库中所有人员的姓名和电子邮件。您不希望公开您的域,因此您创建了一个包含PersonDtoname的班次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 null(坏主意)或创建一个新的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 "john.doe@gmail.com"
                     :ssn "1234567890"} :name :email)
; -> {:email "john.doe@gmail.com", :name "John Doe"}

操纵一个人名单:

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

同时向个人添加临时数据也很容易:

(assoc person :tweets tweets)

这不会破坏任何事情。在Java中如果你的对象是不可变的,它们可能没有setter,所以你必须编写很多样板来修改一个字段(new Person(oldPerson.getName(), oldPerson.getEmail(), tweets)),或者创建一个全新的类。可变对象提供了一个很好的API(oldPerson.setTweets(tweets)),但很难测试和理解。

<强>测试

许多Java代码基于某些状态,即使不需要它也是如此。这意味着您可以模拟此状态,这通常意味着额外的样板,如果您还没有创建具有可测试性的代码,则会变得更难。另一方面,没有模拟的测试通常很慢,并且取决于数据库访问或时间或其他肯定会在您不时失败的事情。

在编写Clojure的同时,我注意到我实际上并不需要那么多状态。几乎唯一的情况是我从“外部”检索某些东西,无论是数据库还是某些Web服务。

<强>摘要

我的代码是一个管道,从一端我获得了一些数据,然后通过过滤,转换或将其与其他一些数据连接,直到它到达管道末端,然后在管道中更改此数据。在管道内部没有必要真正改变数据,但很多情况下强大的函数和不可变的数据结构是有用的,这就是为什么Clojure使用这样的代码创造奇迹。

答案 1 :(得分:5)

答案 2 :(得分:1)

几个月前,我遇到了同样的问题,我们决定解决Clojure中的“蒙娜丽莎”问题。结果是this presentation。基本上我们表明Clojure对于解决“代码为数据”提供优雅解决方案的问题非常酷。例如,在遗传算法中。