如何制作代表数字子集的数据结构?

时间:2019-06-28 19:16:22

标签: types elm

我想知道是否有一种方法可以制作类似Int类型的内容,该类型只能表示数字的某个子集(例如0〜29),并且如果您尝试执行其他操作,则使编译器抛出错误用它。

我知道我可以做类似type MoonPhaseDay = Day1|Day2| ... |Day29的事情,但这并不能扩大范围。

我试图牢记“使不可能的状态无法代表”的建议。我可以通过Int来解决,但是我很好奇是否有更好的方法。

2 个答案:

答案 0 :(得分:2)

您正在寻找的东西有时被称为“从属类型”,并且今天不属于Elm。

但是,通过在其自己的模块中创建一个类型,而不是导出原始类型构造函数,而仅导出您提供的自定义函数(使其成为“不透明类型”),您可以获得类似的结果。这样,该模块包含了唯一需要保护的代码。


This answer by Nathan在了解不透明类型时可能会有所帮助。

答案 1 :(得分:0)

您需要使用智能构造函数。您可以通过控制从模块导出的内容来强制执行约束。

module Bounded exposing (Bounded, fromInt, toInt)


type Bounded
  = Bounded Int


fromInt : Int -> Maybe Bounded
fromInt n =
  if n < 0 || n > 29 then
    Nothing
  else
    Just (Bounded n)


toInt : Bounded -> Int
toInt (Bounded n) = n

说明

Bounded类型被定义为具有一个数据构造函数的联合类型。导出类型时,我们不会导出构造函数,即它不是公共API的一部分。这称为不透明类型

该模块的用户只能使用Bounded创建fromInt类型。 fromInt被称为智能构造函数,因为它具有一些逻辑(智能)来执行约束。

如果需要使用整数进行换行,请使用toInt。保证toInt总是返回0到29之间的一个整数。没有隐藏的后门可以包装任何其他整数。

HaskellWiki在smart constructors上写得很好。

最后,理查德·费尔德曼(Richard Feldman)在他的演讲“镀金玫瑰的类型和测试”中,通过一个不错的示例here来解释了您想要做什么。