模式匹配标记的联合类型

时间:2018-03-02 06:20:53

标签: elm algebraic-data-types

我有一个标记的联合类型,其中包含一些记录数据,比如

type Comment = New Content | Edited Content | Flagged Content

type alias Content = {id: Int, text: String}

Comment类型声明状态。

当使用模式匹配例如按id过滤时,我必须写

filter Int -> Comment -> Bool
filter id comment =
  case comment of
    New content -> content.id == id
    Edited content -> content.id == id
    Flagged content -> content.id = id

这很有效,但我必须为每个案例复制相同的逻辑,而不是像我一样简单

 filter id comment =
   case comment of
     _ content -> content.id == id

使用过滤这样的功能这是简单的一行重复,但在基于状态呈现内容时,HTML生成逻辑的重复更严重。

据我所知,在Elm中,联盟类型可以携带不同的有效载荷#34;并且编译器不喜欢通用版本,但是在这种情况下有一些方法告诉编译器所有这些情况都处理相同的记录类型?

或者这是一种无效使用联合类型的情况,模型的结构应该不同?也许国家是记录类型的一部分。

2 个答案:

答案 0 :(得分:4)

  

或者这是一种无效使用联合类型的情况,模型的结构应该不同吗?

如果所有三个变体都将包含相同的数据,那么是。

我会在顶部使用记录,并为评论的“状态”创建一个标记的联合。

type alias Comment =
    { id : Int
    , text : String
    , status : Status
    }


type Status
    = New
    | Edited
    | Flagged

这样可以轻松访问评论的idtext。如果你case comment.status of ...,你仍然可以获得详尽的模式匹配的好处。

答案 1 :(得分:3)

您可以分解获取内容部分

type Comment = New Content | Edited Content | Flagged Content

type alias Content = {id: Int, text: String}

filter : Int -> Comment -> Bool
filter id comment =
  let content = commentContent comment
  in  content.id == id

commentContent : Comment -> Content
commentContent comment =
  case comment of
    New content -> content
    Edited content -> content
    Flagged content -> content

您可以进一步抽象,例如,如果您想添加文本过滤器

filter : Int -> Comment -> Bool
filter id comment =
  doFilter (\c -> c.id == id) comment

filterText : String -> Comment -> Bool
filterText text comment =
  doFilter (\c -> c.text == text) comment

doFilter : (Content -> Bool) -> Comment -> Bool
doFilter f comment =
  let content = commentContent comment
  in  f content

最后,添加一些功能风格......

doFilter : (Content -> Bool) -> Comment -> Bool
doFilter f = f << commentContent