有没有办法在Clojure中创建约束数据类型?

时间:2015-08-30 12:36:57

标签: clojure

例如,一个只包含有效电子邮件地址的字符串,由某些正则表达式定义。

如果此类型的字段是更复杂数据结构的一部分,或者将用作函数参数,或在任何其他上下文中使用,则客户端代码将能够假设该字段是包含字符串的字符串有效的电子邮件地址。因此,没有像“有效”的检查吗?应该是必要的,因此domaintypes的方法不起作用。

在Haskell中,这可以通过smart constructor (section 1.2)和Java来完成,确保类型是不可变的(所有setter私有),并在构造函数中添加一个检查,如果用于创建类型的字符串则抛出RuntimeException不包含有效的电子邮件地址。

如果在简单的Clojure中这是不可能的,我希望在一些众所周知的语言扩展中看到一个示例实现,如Typed Clojure

1 个答案:

答案 0 :(得分:1)

好吧,也许,我现在明白了一个问题,我在评论中提出了我的想法并不是很好。所以我试着为你的问题建议一个可接受的解决方案,然后我试着解释一下我试图在评论中提出的一些想法。

1)有一个gen-class为类生成编译的字节码,你可以在那里设置类的构造函数。

2)您可以在某个名称空间中创建record defrecord,该名称空间在您的项目中按惯例隐私,然后您 使用public api创建另一个命名空间,并在此处定义工厂函数。因此,公共命名空间的用户只能调用公共命名空间的公共函数。 (当然,他也可以打电话给私人,但还有其他代码)

3)你可以定义一个像make-email这样的函数来返回map。 所以你没有在任何地方指定你的数据结构。

4)您可以将代码记录在哪里,警告人们使用工厂功能进行施工。

但是!在Java中,如果您的代码需要某些接口,那么为您的代码提供有效的接口实现是一个用户问题。因此,如果您在Java中编写一些通用代码,那么您已经失去了有效电子邮件字符串的属性。带接口的东西是因为Java是静态类型语言。

一般来说,Clojure是动态类型的,因此用户通常应该能够将任意数据结构传递给任意函数,而不会在编译时出现任何类型问题,如果他传递了错误的数据,那就是他的错。例如,这使得这件事成为可能:你创建一个record并创建一个工厂(构造函数)函数。并且您希望在代码中传递record。但是,用户可以使用与map字段名称相同的密钥传递record,代码也可以使用。

因此,一般来说,如果您希望代码的用户负责传递所需类型的动态类型语言,那么用户负责以正确的方式构建它并不需要任何费用。

另一种解决方案是:用户只需编写测试。您可以在api函数:pre:post条件中指定以检查结构。你可以使用类型化的clojure与我上面写的想法。你可以使用一些额外的声明性库,就像@Thumbnail的第一个评论中提到的那样。

P.S。我不是一个专业人士,所以我很容易错过一些更好的解决方案。