Elm 中 'HTML msg' 中的 'msg' 实际上是什么?

What is the 'msg' in 'HTML msg' in Elm actually?

我正在自学 elm 并看到(当然)许多对 Html msg--

的引用

我知道这是一个 'parameterised type',也就是说(据我了解),Html 类型的构造函数接受一个参数——与 List Char 差不多

好的。但是在接下来的一些教程中,我看到他们很快将 msg 更改为自定义类型,通常是这样的(我凭记忆这样做,所以请原谅我):

Html Msg

其中 Msg 可能定义为

type Msg =
  Something | SomethingElse

我在这里也看到了 -- https://discourse.elm-lang.org/t/html-msg-vs-html-msg/2758 -- 他们说

The lower case msg is called a type variable. The upper case Msg is called a concrete type - its something your application has defined.

这部分回答了我的问题,但有人可以详细说明这到底是什么意思吗?因为当我看到像List String这样的东西时,我明白String在这个上下文中是什么意思,但是我不明白msgHtml msg中是什么意思。

此外,我们不是在更改函数的 return 值的类型吗?也就是说,如果 Elm 运行时期望 view 到 return 某个类型,并且该类型是 Html msg,如果我们将 return 类型更改为 Html Whatever ,为什么会这样? (例如,我们不能将函数的 return 值从 List String 任意更改为 List Number,对吗?)

来自 OOP 和 C、TypeScript 等类型化语言的背景,我认为任何 Msg 都需要以某种方式与 msg 相关,即 'extend' 它以某种方式允许多态性。显然我的看法是错误的,如有任何解释,我们将不胜感激!

tl;dr:只要每个函数都同意 msgmodel 的类型,它们可以是任何你想要的。

就像List的类型参数一样,msg可以是任何东西。没有限制。为了演示,这是经典的 increment/decrement 示例,其中 msg 只是一个 Int:

-- These type aliases aren't needed, but makes it easier to distinguish
-- their roles in later type signatures
type alias Model = Int
type alias Msg = Int


update : Msg -> Model -> Model
update msg model =
    model + msg


view : Model -> Html Msg
view model =
    div []
        [ button [ onClick 1 ] [ text "+1" ]
        , div [] [ text <| String.fromInt model.count ]
        , button [ onClick (-1) ] [ text "-1" ]
        ]


main : Program () Model Msg
main =
    Browser.sandbox { init = 0, view = view, update = update }

那么它是如何工作的呢?关键在于 Browser.sandbox 函数,因为它将所有内容连接在一起。它的类型签名是:

sandbox :
    { init : model
    , view : model -> Html msg
    , update : msg -> model -> model
    }
    -> Program () model msg

其中 modelmsg 是类型变量。这两个都可以用任何具体类型替换,只要它符合此签名中给出的约束,即它们在 initview 和 [=24 中必须相同=] 函数。否则我们会在这里得到一个类型错误。例如,如果 update 需要 String 而不是 Int,我们将得到错误:

This argument is a record of type:

    { init : Model, update : String -> Model -> Model, view : Model -> Html Msg
    }

But `sandbox` needs the 1st argument to be:

    { init : Model
    , update : String -> Model -> Model
    , view : Model -> Html String
    }

当然也不知道是对还是错,就是不匹配。但为了提供帮助,它假设 String 是正确的,并期望 view 到 return Html String 相反。

我希望这足以回答您的问题。如果没有,请评论并订阅!

你的问题的答案最好用例子来说明。

简短的说明:

我有一个这样的圣诞功能:

wrapPresents : presents -> String

但是类型是什么,presents?它可以是任何你想要的!您可以将其替换为您自己的 'concrete type'。 presents 只是一个占位符!

wrapPresents : Boxes -> String wrapPresents boxes = "All the boxes are now wrapped!"

总结:msg(小写)只是一个占位符