为什么当它们是同一类型时编译器告诉我 "Type misMatch for App message"

Why is is the compiler telling me "Type misMatch for App message" when they are the same type

所以,我一直在和编译器争论类型错误。

这段代码在几天前是有效的。

应用级消息类型不匹配

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

App.update里面match的两个分支有不同的类型。第一个分支的类型为 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