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)
很多事情对我来说变得更加清晰。当我尝试自己制作时,问题出现了。所以,请买票!问题导入三种类型,称为Ticket、Status和User,我应该编写一个函数来接收票证和用户并返回修改后的票证,如给定的示例:
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)
这里的问题是这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要这样设计这个类型。它似乎不必要地复杂并引起混乱。所以请不要为此感到太难过!