如何避免在动态类型语言中创建ad-hoc类型系统?

drf*_*oob 19 erlang types programming-languages functional-programming

在我没有使用类型系统的语言中开始的每个项目中,我最终开始发明一个运行时类型系统.也许"类型系统"这个词太强大了; 至少,当我使用复杂数据类型时,我创建了一组类型/值范围验证器,然后我觉得需要对可以创建和修改数据类型的位置保持偏执.

直到现在我才三思而后行.作为一名独立的开发人员,我的方法已经在一些小项目中实践,并且没有理由他们现在停止工作.

尽管如此,这一定是错的.我觉得好像我没有"正确"使用动态类型的语言.如果我必须发明一个类型系统并自己强制执行,我也可以使用一种类型的语言.

所以,我的问题是:

  • 现有的编程范例(对于没有类型的语言)是否避免使用或发明类型系统的必要性?
  • 是否存在关于如何解决静态类型在动态类型语言中解决的问题的共同建议(没有羞怯地重新发明类型)?

以下是您需要考虑的具体示例.我正在使用erlang中的日期时间和时区(一种动态的强类型语言).这是我使用的常见数据类型:

{{Y,M,D},{tztime, {time, HH,MM,SS}, Flag}}
Run Code Online (Sandbox Code Playgroud)

...其中{Y,M,D}是表示有效日期的元组(所有条目都是整数),tztime并且time是原子,HH,MM,SS是表示24小时合理时间的整数,并且是原子Flag之一u,d,z,s,w.

此数据类型通常从输入中解析,因此为了确保有效输入和正确的解析器,需要检查值的类型是否正确,以及有效范围.稍后,将此数据类型的实例相互比较,使其值的类型更加重要,因为所有术语都会进行比较.来自erlang参考手册

number < atom < reference < fun < port < pid < tuple < list < bit string
Run Code Online (Sandbox Code Playgroud)

Pee*_*ger 7

除了静态与动态以及强与弱类型的混淆:

大多数现有的静态类型系统并未真正解决您希望在示例中实现的内容.无论您使用何种类型的系统,通常在运行期间检查范围检查和并发症(如2月31日)以及特别是已解析的输入.

您在Erlang中的示例我有一些建议:

  • 使用记录.除了对一大堆原因有用和有用之外,无需花费太多精力即可轻松进行运行时类型检查,例如:

    is_same_day(#datetime{year=Y1, month=M1, day=D1}, 
                #datetime{year=Y2, month=M2, day=D2}) -> ...
    
    Run Code Online (Sandbox Code Playgroud)

    Effortless仅匹配两个日期时间记录.如果源不受信任,您甚至可以添加防护来检查范围.并且它符合erlangs让它崩溃的错误处理方法:如果找不到匹配,你会得到一个坏匹配,并且可以在它适当的级别(通常是主管级别)处理它.

  • 通常编写代码,当假设无效时它会崩溃

  • 如果没有足够的静态检查:使用typerdialyzer查找可以静态找到的错误类型,将在运行时检查剩余的内容.

  • 在你的函数中,你接受的"类型"不要过于严格,有时即使对于不同的输入,仅仅做一些有用的附加功能比检查每个函数的类型和范围更有价值.如果你在通常很重要的地方这样做的话,你会尽早发现错误,以便于修复.对于函数式语言尤其如此,在这种语言中,您总是知道每个值的来源.


900*_*000 1

有时数据需要验证。验证从网络接收到的任何数据几乎总是一个好主意 \xe2\x80\x94 尤其是来自公共网络的数据。在这里偏执是好事。如果类似静态类型系统的东西可以以最不痛苦的方式帮助做到这一点,那就这样吧。Erlang 允许类型注释是有原因的。甚至模式匹配也可以被视为一种动态类型检查;尽管如此,它是该语言的一个核心特征。在 Erlang 中,数据的结构就是它的“类型”。

\n\n

好处是,您可以根据需要定制“类型系统”,使其灵活且智能,而 OO 语言的类型系统通常具有固定的功能。当您使用的数据结构是不可变的时,一旦您验证了这种结构,您就可以安全地假设它符合您的限制,就像静态类型一样。

\n\n

准备好在程序的任何点处理任何类型的数据(无论是否动态类型)都是没有意义的。“动态类型”本质上是所有可能类型的联合;将其限制为有用的子集是一种有效的编程方法。

\n