【问题标题】:How to read type definitions in Elm如何在 Elm 中读取类型定义
【发布时间】:2019-01-30 22:12:26
【问题描述】:

我应该如何阅读如下的类型定义?

type Config data msg =
  Config
    { toId : data -> String
    , toMsg : State -> msg
    , columns : List (ColumnData data msg)
    , customizations : Customizations data msg
    }

它似乎有一个“重复”元素:Config 出现在 LHS 和 RHS 上。

另一个例子是这样的:

type State =
  State String Bool

这些类型声明在传达什么信息?

【问题讨论】:

    标签: types syntax elm


    【解决方案1】:

    左侧命名您将创建的类型。在右侧,您将定义该类型实际可以采用的值。可以只有一个,也可以随心所欲。

    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
    

    许多有用的核心功能,如MaybeResult 实际上是接受参数的类型。它们也被称为抽象类型。要使它们成为具体类型,您需要将具体类型 [^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 并返回StringtoMsg 是一个从StateInt 的函数,等等。

    欲了解更多信息,请参阅https://guide.elm-lang.org/types/custom_types.html

    [^1]:像 Haskell 这样的一些语言实际上允许更狂野的类型。 https://wiki.haskell.org/Kind

    【讨论】:

    • 数据构造函数在 Elm 中被称为变体,顺便说一句。我也很确定参数化类型构造函数不称为抽象类型。关于类型的抽象通常意味着实现是隐藏的,而使用自定义类型这样做的能力是,我认为,使用单个构造函数自定义类型而不是别名的唯一原因。
    • 谢谢,我已切换到变体术语。尽管我不清楚它是指数据构造函数还是整个总和。我有seen 用于此类事物的抽象术语,尽管它不是类型被认为是抽象的唯一情况——而且该术语已经有很多用途,包括 ADT 术语。也许与 inhabited type 对应的词会更好,但我不知道。
    • 有趣。我认为使用更广泛且 IMO 不太容易混淆的术语是“通用”,而不是“具体”。
    • 我认为泛型是指在 OOP 语言中具有非空类型构造函数的类型。用这种说法,具体类型将是(完全)专用的泛型类型。
    • 真的有区别吗?除了文化或观点?无论哪种方式,正如我之前所说,我认为StateConfig 的目的都是通过不导出数据构造函数来使类型抽象,这与您在答案中使用该术语的方式不同.即使在技术上是正确的,我也觉得它很混乱。是否可以以某种方式对这两个术语进行限定以消除它们的歧义?
    猜你喜欢
    • 2018-04-06
    • 1970-01-01
    • 2022-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-01
    • 1970-01-01
    • 2020-04-01
    相关资源
    最近更新 更多