用“as”词解构 Elm 中的记录

dud*_*-av 3 functional-programming elm

我又在做Exercism中的Elm练习,到目前为止我还不清楚一件事。“as”解构如何工作?一开始我什么都不懂。在阅读了 Yang Wei 的Elm 解构(或模式匹配)备忘单后,更具体地说这部分:

myRecord = { x = 1, y = 2, z = 3}

computeSomething ({x, y} as wholeRecord) =
    -- x and y refer to the x and y fields of the passed in record
    -- wholeRecord is the complete record
    -- i.e. x and wholeRecord.x refer to the same field
    -- but z is only accessible as wholeRecord.z
Run Code Online (Sandbox Code Playgroud)

很多事情对我来说变得更加清晰。当我尝试自己制作时,问题出现了。所以,请买票!问题导入三种类型,称为TicketStatusUser,我应该编写一个函数来接收票证和用户并返回修改后的票证,如给定的示例:

assignTicketTo (User "Danny")
    (Ticket
        { status = New
        , createdBy = ( User "Jesse", 3 )
        , assignedTo = Just (User "Alice")
        , comments = [ ( User "Jesse", "I've been waiting for 6 months!!" ) ]
        }
    )
-- => Ticket
--        { status = InProgress
--        , createdBy = ( User "Jesse", 3 )
--        , assignedTo = Just (User "Danny")
--        , comments = [ ( User "Jesse", "I've been waiting for 6 months!!" ) ]
--        }
Run Code Online (Sandbox Code Playgroud)

大问题就在这里,因为在解构Ticket变量并使用as将其归因于不同的变量(如下所示)之后,语言告诉我新变量具有不同的类型,即它不是Ticket

assignTicketTo : User -> Ticket -> Ticket
assignTicketTo user ({ status, assignedTo } as ticket) =
    if (status == New) then
        { ticket | status = InProgress, assignedTo = Just user }
    else
        ticket
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?当我尝试在 Elm 中解构类型时,我读到了关于类型不匹配的答案,但我能想象我可能做错的唯一一件事,即解构,也不正确:

assignTicketTo : User -> Ticket -> Ticket
assignTicketTo user (Ticket { status, assignedTo } as ticket) =
    if (status == New) then
        { ticket | status = InProgress, assignedTo = Just user }
    else
        ticket
Run Code Online (Sandbox Code Playgroud)

编辑:错误消息是:

This is not a record, so it has no fields to update!

45|         Ticket { ticket | status = InProgress, assignedTo = Just user }
                     ^^^^^^
This `ticket` value is a:

    Ticket

But I need a record!
Run Code Online (Sandbox Code Playgroud)

The 2nd argument to `assignTicketTo` is weird.

43| assignTicketTo user ({ status, assignedTo } as ticket) =
                         ^^^^^^^^^^^^^^^^^^^^^^
The argument is a pattern that matches record values of type:

    { c | assignedTo : a, status : b }

But the type annotation on `assignTicketTo` says the 2nd argument should be:

    Ticket
Run Code Online (Sandbox Code Playgroud)

gle*_*nsl 6

这里的问题是这Ticket不是记录类型。它是一种自定义类型,具有包含记录的单个变体。它的定义(这是您应该在问题中发布的基本上下文)是:

type Ticket
    = Ticket
        { status : Status
        , createdBy : ( User, Int )
        , assignedTo : Maybe User
        , comments : List ( User, String )
        }
Run Code Online (Sandbox Code Playgroud)

要解构它,您必须首先解开自定义类型,然后解开记录并为其指定一个名称:

Ticket ({ status, assignedTo } as ticket)
Run Code Online (Sandbox Code Playgroud)

然后要Ticket再次返回 a,您还必须在更新记录后将记录重新包装在Ticket构造函数中。因此,完整的工作函数是:

assignTicketTo : User -> Ticket -> Ticket
assignTicketTo user (Ticket ({ status, assignedTo } as ticket)) =
    if status == New then
        Ticket { ticket | status = InProgress, assignedTo = Just user }

    else
        Ticket ticket
Run Code Online (Sandbox Code Playgroud)

我不知道为什么Ticket要这样设计这个类型。它似乎不必要地复杂并引起混乱。所以请不要为此感到太难过!