我正在自学榆木,并且(当然)看到许多对Html msg
-
我知道这是一个“参数化类型”,也就是说,(据我所知),类型Html
的构造函数需要一个参数-与List Char
一样。 / p>
好。但是随后在一些教程中,我发现他们很快将msg
更改为自定义类型,通常是这样的(我是从内存中做的,所以请原谅我):
Html Msg
其中Msg
可能定义为
type Msg =
Something | SomethingElse
我也看到了-https://discourse.elm-lang.org/t/html-msg-vs-html-msg/2758-他们说
小写的味精称为类型变量。大写的Msg称为具体类型-您的应用程序已定义的类型。
那部分回答了我的问题,但是有人可以详细说明这到底意味着什么吗?因为当我看到类似List String
之类的内容时,我了解了String
在这种情况下的含义,但是我不了解msg
在Html msg
中的含义。
此外,我们是否不更改函数返回值的类型?也就是说,如果Elm运行时期望view
返回某个类型,并且该类型为Html msg
,那么如果我们将返回类型更改为Html Whatever
,那为什么可行? (例如,我们不能将函数的返回值从List String
任意更改为List Number
,对吗?)
来自OOP的背景以及诸如C,TypeScript等类型语言的背景,我认为任何Msg
都需要以某种方式与msg
相关,即在某些情况下将其“扩展”多态的方法。显然,我是用错误的方式看待的,任何解释将不胜感激!
答案 0 :(得分:7)
tl; dr :只要每个函数都同意msg
和model
的类型,它们可以是您想要的任何东西。
就像List
的类型参数一样,msg
可以是任何东西。没有限制。为了演示,这是经典的增量/减量示例,其中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
其中model
和msg
是类型变量。只要符合此签名中给出的约束,这两个都可以用任何具体类型替换,即它们在init
,view
和{{1 }} 功能。否则,我们将在此处收到类型错误。例如,如果update
需要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
。
我希望能充分回答您的问题。如果没有,请发表评论并订阅!
答案 1 :(得分:1)
最好用例子来说明问题的答案。
圣诞节快到了(快到2019年12月了),我有这样的功能:
wrapPresents : presents -> String
但是presents
是什么类型?可以是您想要的任何东西!您可以用自己的“混凝土类型”代替它。 presents
只是一个占位符!
wrapPresents : Boxes -> String
wrapPresents boxes =
"All the boxes are now wrapped!"