Clojure的好展示是什么?

7

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

我想举办一场关于Clojure的讨论会。您能否推荐一个可以用Clojure函数式编程优雅地解决的问题?您能指出涵盖此主题的资源吗?

你需要什么样的会话?你是在寻找一个可以在一小时、一天或一周内解决的问题和解决方案吗?有很多可能性。 - Justin Kramer
我们有一个公司范围内的定期展示活动,以展示新技术。这是一个为期2小时的实践课程。 - spa
3个回答

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服务,用于检索数据库中所有人的姓名和电子邮件。您不想暴露您的领域,所以创建了一个类 PersonDto,其中包含nameemail。这很容易,现在您需要编写一个函数来将数据从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 "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对于这种代码起到奇妙作用的原因。

我喜欢那个摘要。那正是我在使用Clojure三个月的感受。 - Amogh Talpallikar

5

1
几个月前,我遇到了同样的问题,我们决定用Clojure解决“蒙娜丽莎”问题。结果是this presentation。基本上,我们展示了Clojure在解决“代码即数据”能够提供优雅解决方案的问题方面非常出色,例如在遗传算法中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接