Elm "type" 语法——价值从何而来?

Elm "type" syntax - where is value coming from?

我是新手,目前正在尝试学习 Elm。我来自 JS/React,以前没有任何 RFP 经验。

我在指南中: http://guide.elm-lang.org/architecture/user_input/text_fields.html

我遇到问题的部分是 updateview:

-- UPDATE

type Msg
  = Change String

update : Msg -> Model -> Model
update msg model =
  case msg of
    Change newContent ->
      { model | content = newContent }


-- VIEW

view : Model -> Html Msg
view model =
  div []
    [ input [ placeholder "Text to reverse", onInput Change ] []
    , div [] [ text (String.reverse model.content) ]
    ]

让我们从 Msg 声明开始。指南说:

It takes one argument, in this case the Change function which was created when we declared the Msg type:

Change : String -> Msg

我不明白这是怎么发生的:

type Msg
  = Change String

我们这里是怎么定义Change函数的?我们如何定义该功能的工作原理?在我看来,我们只是声明了 Msg 的类型,它以某种方式包含了 Change 和类型 String

我的第二个问题是关于更新的:

update : Msg -> Model -> Model
update msg model =
  case msg of
    Change newContent ->
      { model | content = newContent }

对我来说,update 是一个高阶函数,它接受一个 Msg 和 returns 一个函数 Model -> Model。但是随后我们定义了一个带有两个参数的函数。 Msg -> Model -> Model 是否仅表示除最后一部分之外的所有参数?

然后我们调用Change函数:

Change newContent ->
          { model | content = newContent }

我不明白那里的箭头。通常箭头出现在参数定义之后。但是这里我们有 ->.

之前函数的结果

我希望我的问题是有道理的,我只是对这种(大概很棒的)语言感到很困惑。

当您声明 type Msg = Change String 时,您是在声明一种类型 (Msg),其中包含一个接受字符串的构造函数。

请参阅有关 Union Types(也称为代数数据类型,ADT)的 Elm 指南部分。

这是一个示例:

type User = Anonymous | Named String

So creating the type User also created constructors named Anonymous and Named. If you want to create a User you must use one of these two constructors

构造函数是函数,所以你可以这样称呼它们 Change "a string"(returns 类型 Msg

构造函数还提供了使用模式匹配 提取联合类型中的内部值的能力。这是你不熟悉的->的用法。

case msg of
  Change theString -> ... use theString ...

你的第二个问题;

To me this looks like update is a higher order function, which takes a Msg and returns a function Model -> Model

是的,这或多或少是正在发生的事情。函数应用的优先规则意味着您可以不带括号地调用它们。这称为 currying,并且在 elm 指南

中也有介绍

只是为了更清楚地说明第二部分:

所有函数都是柯里化的,这意味着 update: Msg->Model->Model 可以接收一个 Msg 和 return 一个函数 Model->Model 或者接收一个 Msg 和一个 Model 和 return 一个 Model.

实际上,当您调用 update aMessage aModel 时,您实际上是在调用 update aMessage,其中 return 是一个函数,然后您将 aModel 传递给该函数,该函数将 运行 函数体中的表达式和 return 更新后的模型。

箭头只是 case.. of 语法的一部分。左边是你要匹配的模式,右边是你要执行的表达式。在您的情况下,仅当使用 Change 构造函数创建 Msg 时,您的更新才会执行表达式。

type Msg
  = Change String | Delete

update : Msg -> Model -> Model
update msg model =
  case msg of
    Change newContent ->
      { model | content = newContent }
    Delete ->
      { model | content = "" }

在前面的例子中,Msg 可以用Change StringDelete 构造。根据 msg 的构造方式,更新函数的行为有所不同。