Почему компилятор сообщает мне "Неправильное соответствие типа для сообщения приложения", когда они одного типа

Итак, я борюсь с компилятором из-за ошибки типа.

Этот код работал пару дней назад.

Введите misMatch для сообщения уровня приложения

Фрагменты App.fs

module App =
    type Msg =
        | ConnectionPageMsg of ConnectionPage.Msg
        | CodeGenPageMsg of CodeGenPage.Msg
//...
    let update (msg : Msg) (model : Model) =
        match msg with
        | ConnectionPageMsg msg ->
            let m, cmd = ConnectionPage.update msg model.ConnectionPageModel
            { model with ConnectionPageModel = m }, cmd
        | CodeGenPageMsg msg ->
            let m, cmd = CodeGenPage.update msg model.CodeGenPageModel
            { model with CodeGenPageModel = m }, cmd
//...
    let runner =
        Program.mkProgram init update view
        |> Program.withConsoleTrace
        |> XamarinFormsProgram.run app

Я добавил явные псевдонимы и исходную ошибку:

Type mismatch. Expecting a
    'App.Msg -> App.Model -> App.Model * Cmd<App.Msg>'    
but given a
    'App.Msg -> App.Model -> App.Model * Cmd<Msg>'    
The type 'App.Msg' does not match the type 'Msg'

Стали такими:

App.fs(50,50): Error FS0001: The type 'PocoGen.Page.ConnectionPage.Msg' does not match the type 'PocoGen.Page.CodeGenPage.Msg' (FS0001) (PocoGen)
App.fs(32,32): Error FS0001: Type mismatch. 
Expecting a 'App.Msg -> App.Model -> App.Model * Cmd<App.Msg>'    
but given a 'App.Msg -> App.Model -> App.Model * Cmd<Msg>'    
The type 'App.Msg' does not match the type 'Msg' (FS0001) (PocoGen)

Прочие замечания

Прямо перед тем, как эти ошибки начали появляться, я работал над преобразованием блокирующего синхронного вызова в асинхронную команду в ConnectionTestPage и удалил вызывающий код для cmd, надеясь, что это исправит. (Это не так)

Сообщения ConnectionPage.fs

type Msg =
    | UpdateConnectionStringValue of string
    | UpdateConnectionStringName of string
    | TestConnection
    | TestConnectionComplete of Model
    | SaveConnectionString of ConnectionStringItem
    | UpdateOutput of string

Обновление ConnectionPage.fs

let update (msg : Msg) (m : Model) : Model * Cmd<Msg> =
    match msg with
    | UpdateConnectionStringValue conStringVal ->
        { m with
              ConnectionString =
                  { Id = m.ConnectionString.Id
                    Name = m.ConnectionString.Name
                    Value = conStringVal }
              CurrentFormState =
                  match hasRequredSaveFields m.ConnectionString with
                  | false -> MissingConnStrValue
                  | _ -> Valid }, Cmd.none

    | UpdateConnectionStringName conStringName ->
        { m with
              ConnectionString =
                  { Id = m.ConnectionString.Id
                    Name = conStringName
                    Value = m.ConnectionString.Value }
              CurrentFormState =
                  match hasRequredSaveFields m.ConnectionString with
                  | false -> MissingConnStrValue
                  | _ -> Valid }, Cmd.none

    | UpdateOutput output -> { m with Output = output }, Cmd.none
    | TestConnection -> m, Cmd.none
    | TestConnectionComplete testResult -> { m with Output = testResult.Output + "\r\n" }, Cmd.none
    | SaveConnectionString(_) -> saveConnection m, Cmd.none

Я играл с версией Fsharp (потому что, кстати, я обновился до 4.7.2 немного до получения этой ошибки)

Полное репо:

https://github.com/musicm122/PocoGen_Fsharp/tree/master/PocoGen

1 ответ

Решение

Две ветви match внутри App.updateбывают разные типы. Первая ветка имеет типApp.Model * Cmd<ConnectionPage.Msg> а вторая страница имеет тип App.Model * Cmd<CodeGenPage.Msg>.

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

let x = 
    match y with
    | true -> 42
    | false -> "foo"

Какой тип xВот? Этоint или это string? Не вычисляет. Аmatch выражение должно иметь все ветви одного типа.


Конвертировать Cmd<ConnectionPage.Msg> в Cmd<App.Msg> (заключив сообщение в ConnectionPageMsg) вы можете использовать Cmd.map:

let update (msg : Msg) (model : Model) =
    match msg with
    | ConnectionPageMsg msg ->
        let m, cmd = ConnectionPage.update msg model.ConnectionPageModel
        { model with ConnectionPageModel = m }, Cmd.map ConnectionPageMsg cmd
    | CodeGenPageMsg msg ->
        let m, cmd = CodeGenPage.update msg model.CodeGenPageModel
        { model with CodeGenPageModel = m }, Cmd.map CodeGenPageMsg cmd
Другие вопросы по тегам