Что означает функция с 2 значениями в правой части? (Модель → Html msg)

Я столкнулся с этим в руководстве:

viewValidation : Model -> Html msg
viewValidation model =
  let
    (color, message) =
      if model.password == model.passwordAgain then
        ("green", "OK")
      else
        ("red", "Passwords do not match!")
  in
    div [ style [("color", color)] ] [ text message ]

Итак, это функция, которая принимает значение Model. Html msg обычно выглядит так, как будто мы вызываем функцию Html с аргументом msg.

msg, похоже, не играет никакой роли ни в какой другой части функции viewValidation. Итак, что это значит и что это значит в этом случае?

Ответ 1

Html Msg - это просто параметр типа, поскольку List Int is. Пока List Int обозначает список, содержащий элемент типа Int, аналогично Html Msg описывает некоторый HTML, который может обрабатывать/выдавать сообщения типа Msg.

Например, если у вас есть кнопка внутри HTML, она может выглядеть так:

button [ onClick DoSomething ] [ text "caption" ]

Где DoSomething - это случай типа Msg.

Ответ 2

Не смешивайте определение типа с нормальным выполнением кода. Html не является функцией, это тип, который принимает параметр для определения типа для функции вида.

Html msg - это самое общее определение, которое вы можете иметь в качестве msg - это сама переменная, поэтому это возвращает Html, который не зависит от используемого вами типа msg. Это может быть либо из-за того, что он не создает сообщений о событиях, либо потому, что функция просмотра принимает сообщения как параметры.

Поскольку установленные комментарии Html () были бы очень узким типом, который был бы вынужден ничего не возвращать.

Наиболее распространенным случаем является функция представления, возвращающая Html msg - i.e.Html с сообщениями на основе пользовательских взаимодействий.

Поскольку Elm поощряет компонентность, вам также нужно иметь в виду Html.map. Это подпись типа Html.map : (a -> b) -> Html a -> Html b. В контексте компонентов это легче читать как

Html.map : (Child.Msg -> Parent.Msg) -> Html Child.Msg -> Html Parent.Msg

Обратите внимание, что когда вы определяете свои сообщения в своем родительском компоненте, у вас будет что-то вроде:

type Msg = ChildMsg Child.Msg

что означает, что ChildMsg имеет подпись типа:

ChildMsg : Child.Msg -> Parent.Msg

Таким образом, мои функции просмотра имеют много

parentView model = 
  -- childView model.child |> Html.map ChildMsg
  Html.map ChildMsg (childView model.child)