【问题标题】:Type inheritance in elmelm中的类型继承
【发布时间】:2018-11-16 01:09:03
【问题描述】:

我想要实现的是类型继承。我的意思是我希望能够让函数返回“子类型”,然后函数返回“超类型”。举个例子吧

假设我有一个返回 Html 消息的主视图组件

view:  Model -> Html Msg
view model = 
    div [class "goal-box"] [
      function_a model,
      function_b model
    ]

现在我希望function_afunction_b 都能够返回Msg 的子类型

function_a: Model -> Html AMsg

function_b: Model -> Html BMsg

我想要这个的原因是因为我想确保 function_a 限制它可以产生什么样的 Msg,function_b 也是如此,但最终我需要一个使用两者的统一视图。

所以自然而然的就是将 Msg 定义为

type Msg 
  = AMsg
  | BMsg

type AMsg
  = AnotherMsg Int
  | AgainMsg Int

type BMsg
  = ThisMsg String
  | ThatMsg Int

这似乎不起作用,因为编译器告诉我它期望返回类型为 Html Msg 而不是 Html AMsg

我希望这很清楚。我觉得类型是我在 JS 中最挣扎的概念,但希望我朝着正确的方向前进。

免责声明

我在当天早些时候问过一个类似的问题,但我意识到我犯了一个错误,然后在我编辑它时困惑了几次。所以我不得不删除它。提前向花时间阅读并回答的人道歉。

【问题讨论】:

  • 我认为您尝试做的事情以及您在上一个问题中尝试做的方式非常有意义,并且是 OCaml 中称为多态变体的功能。不幸的是,Elm 不支持它,这可能是因为这种东西存在一些微妙的问题,使其不那么吸引人,尤其是对于面向初学者的语言。
  • @glennsl 是的,我认为这就是您在我的另一个问题中试图向我解释的内容。不幸的是,我措辞错误,还有其他一些错误让我相信继承工作正常。我想过编辑这个问题,但它变得太混乱了,所以我决定删除并重新创建。无论如何,马库斯的回答似乎完成了工作,但我当然希望这更直接一点。将来可能会发生,毕竟我们只是在 0.19 版本

标签: types elm


【解决方案1】:

这里有两个主要问题。

首先,Msg 中的 AMsgBMsg 不指代这些类型,它们只是 Msg 类型的构造函数。

您需要将其更改为:

type Msg 
  = AMsg AMsg
  | BMsg BMsg

这里每行的第一个AMsgBMsgMsg 类型的构造函数,第二个是指您的其他类型。在此之后,您可以创建像 AMsg (AnotherMsg 34) 这样的值。

其次,您需要在 view 中使用函数 Html.map 来更改消息类型,以便在例如function_a 发送消息AnotherMsg 34AMsg 类型),该消息将转换为AMsg (AnotherMsg 34)Msg 类型),因此在您的view 中,所有消息都属于同一类型。

下面的完整示例代码,这里有 ellie 示例:https://ellie-app.com/3TG62zDLvwFa1

module Main exposing (main)

import Browser
import Html exposing (Html, button, div, text)
import Html.Events exposing (onClick)

type alias Model =
    {}

init : Model
init =
    {}

type Msg 
  = AMsg AMsg
  | BMsg BMsg

type AMsg
  = AnotherMsg Int
  | AgainMsg Int

type BMsg
  = ThisMsg String
  | ThatMsg Int

view : Model -> Html Msg
view model = 
    div [] [
      Html.map AMsg (function_a model),
      Html.map BMsg (function_b model)
    ]

function_a : Model -> Html AMsg
function_a model =
    div [] [ text "A" ]

function_b : Model -> Html BMsg
function_b model =
    div [] [ text "B" ]

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

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

【讨论】:

  • 谢谢!确实感觉有点麻烦,但至少它完成了工作
猜你喜欢
  • 2010-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-01
  • 2020-01-05
  • 2018-09-27
  • 2015-09-15
相关资源
最近更新 更多