左侧命名您将创建的类型。在右侧,您将定义该类型实际可以采用的值。可以只有一个,也可以随心所欲。
type MyType = ValueA | ValueB | ValueC
此外,您可以创建其值包含额外数据的类型。这可以通过另一种类型的值名称(正式称为 data constructor,或 Elm 中的 variant)来完成。您可以使用任何具体类型并拥有任意数量的类型。变体之间的类型和参数(参数数量)不需要相同。
type MyType = ValueA String | ValueB Int (List String) | ValueC
这些都是具体的类型。当你有一个值时,它总是有一个具体的类型。假设您要创建自己的配对类型。你可以定义
type PairOfIntAndInt = PairOfIntAndInt Int Int
type PairOfIntAndString = PairOfIntAndString Int String
type PairOfStringAndString = PairOfStringAndString String String
…
但这不会很方便。出于这个原因,Elm 允许您使用带参数的 类型构造函数(即 LHS 上类型名称的正式名称)。它们将用小写字母书写:
type Pair first second = Pair first second
许多有用的核心功能,如Maybe 或Result 实际上是接受参数的类型。它们也被称为抽象类型。要使它们成为具体类型,您需要将具体类型 [^1] 传递给每个参数。
现在,让我们看看您的代码。你有一个类型构造函数Config,它接受两个参数。
type Config data msg =
并且该类型接受使用其一个数据构造函数创建的值
Config
存储单个值。值的类型实际上是一个组合类型,一条记录。它需要四个字段,它们的类型将取决于类型构造函数的参数。
{ toId : data -> String
, toMsg : State -> msg
, columns : List (ColumnData data msg)
, customizations : Customizations data msg
}
例如,如果您有一个具体类型Config String Int,它将期望以下值:
Config
{ toId = someToIdValue
, toMsg = someToMsgValue
, columns = someColumnsValue
, customizations = someCustomizationsValue
}
其中someToIdValue 必须是一个函数,接受String 并返回String,toMsg 是一个从State 到Int 的函数,等等。
欲了解更多信息,请参阅https://guide.elm-lang.org/types/custom_types.html
[^1]:像 Haskell 这样的一些语言实际上允许更狂野的类型。 https://wiki.haskell.org/Kind