Elm中的类型继承 [英] Type inheritance in elm

查看:68
本文介绍了Elm中的类型继承的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



假设我有一个主要的View组件,它返回一个HTML消息

 视图:模型-> HTML消息
视图模型=
div [类目标框] [
function_a模型,​​
function_b模型
]

现在我想要 function_a function_b 到每个能够返回 Msg



function_a的子类型的函数:模型-> HTML AMsg



function_b:模型-> Html BMsg



我之所以想要这样做,是因为我想确保function_a在生成的Msg中受到限制,并且对于function_b同样如此,但最终我需要使用这两者的统一视图。



所以自然而然地将Msg定义为

  type Msg 
= AMsg
| BMsg

类型AMsg
= AnotherMsg Int
| AgainMsg Int

类型BMsg
= ThisMsg字符串
| ThatMsg Int

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



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



免责声明



当天早些时候我也问过类似的问题,但我意识到自己犯了一个错误,然后在编辑时感到困惑。所以我不得不删除它。

解决方案

这里有两个主要问题。

解决方案

p>

首先在 AMsg 和 BMsg > Msg 不引用这些类型,它们只是您的 Msg 类型的构造函数。



您需要将其更改为:

  type Msg 
= AMsg AMsg
| BMsg BMsg

这里首先是 AMsg 和<$每行上的c $ c> BMsg 是 Msg 类型的构造函数,第二个则引用您的其他类型。此后,您可以创建类似 AMsg(AnotherMsg 34)的值。



其次,您需要使用函数 Html.map 在您的视图中更改消息类型,以便 function_a 发送消息另一个消息34 (类型为 AMsg ),将会转换为 AMsg(AnotherMsg 34)(类型为 Msg ),因此在您的查看所有消息都是同一类型。



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

  module主要暴露(主要)

导入浏览器
导入Html暴露(HTML,按钮,div,文本)
导入Html.Event暴露(onClick)

类型别名Model =
{}

init:Model
init =
{}

类型Msg
= AMsg AMsg
| BMsg BMsg

类型AMsg
= AnotherMsg Int
| AgainMsg Int

类型BMsg
= ThisMsg字符串
| ThatMsg Int

视图:模型-> Html Msg
视图模型=
div [] [
Html.map AMsg(function_a模型),
Html.map BMsg(function_b模型)
]

function_a:模型-> HTML AMsg
function_a模型=
div [] [文本 A]

function_b:模型-> HTML BMsg
function_b模型=
div [] [文本 B]

更新:Msg->型号->模型
更新msg模型=
模型

main:Program()模型消息
main =
Browser.sandbox
{init = init
,视图=视图
,更新=更新
}


What I am trying to achieve is type inheritance. What I mean by that is that I want to be able to have functions returning "sub-types" and then a function returning the "super-type". Let me give you an example

let's say I have a main View component which returns an Html Msg

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

Now I would like function_a and function_b to each be able to return a subtype of Msg

function_a: Model -> Html AMsg

function_b: Model -> Html BMsg

The reason why I want this is because I want to make sure function_a is limited in what kind of Msg it can produce, and same goes for function_b, but eventually I need a unified view that uses both.

So what came natural was to define Msg as

type Msg 
  = AMsg
  | BMsg

type AMsg
  = AnotherMsg Int
  | AgainMsg Int

type BMsg
  = ThisMsg String
  | ThatMsg Int

This does not seem to work, as the compiler tells me that it was expecting a return value of type Html Msg and not Html AMsg.

I hope this is clear. I feel like types are the concept I am struggling with the most coming from JS, but hopefully I am headed in the right direction.

DISCLAIMER

I have asked a similar question earlier in the day but I realized I made a mistake and then confused myself a couple of times as I was editing it. So I had to delete it. Apologies in advance to the people that took the time to read it and answer.

解决方案

There are two main issues here.

Firstly AMsg and BMsg in your Msg do not refer to those types, they are just constructors for your Msg type.

You need to change this to:

type Msg 
  = AMsg AMsg
  | BMsg BMsg

Here first AMsg and BMsg on each line are constructors for Msg type, and second ones refer to your other types. After this you can create values like AMsg (AnotherMsg 34).

Secondly you need to use function Html.map in your view to change message types so that when e.g. function_a sends message AnotherMsg 34 (of type AMsg), that will be transformed into AMsg (AnotherMsg 34) (of type Msg) and so in your view all messages are of same type.

Full example code below, with ellie example here: 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
        }

这篇关于Elm中的类型继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆