f# - 返回联合类型而不是联合大小写
问题描述
我有这样的联合类型
type AccountCreated =
{ Owner: string
AccountId: Guid
CreatedAt: DateTimeOffset
StartingBalance: decimal }
type AccountDebited =
{ To: Guid
From: Guid
Description: string
Time: DateTimeOffset
Amount: decimal }
type AccountCredited =
{ To: Guid
From: Guid
Description: string
Time: DateTimeOffset
Amount: decimal }
type AccountEvent =
| Created of AccountCreated
| AccountCredited of AccountCredited
| AccountDebited of AccountDebited
还有一个像这样的联合类型:
type RegisteredAccount = {
Owner: string
Balance: decimal
AccountId: Guid }
type Account =
| Unregistered
| Registered of RegisteredAccount
有一个功能evolve
:
let evolve state event: Account =
match event with
| Created accountCreated ->
{ AccountId = accountCreated.AccountId
Owner = accountCreated.Owner
Balance = accountCreated.StartingBalance }
| AccountDebited accountDebited ->
match state with
| Registered s ->
{ s with
Balance = s.Balance - accountDebited.Amount }
| _ -> failwith "unregistered account can't be debited"
| _ -> failwith "todo: other cases"
evolve
应该使用List.fold
:
let build = List.fold evolve
let rebuild = build Unregistered
如果我没有明确指定evolve
as的返回类型Account
,则会收到以下错误let build = List.fold evolve
:
Type mismatch. Expecting a 'Account -> AccountEvent -> Account' but given a 'Account -> AccountEvent -> RegisteredAccount' The type 'Account' does not match the type 'RegisteredAccount'
如果将返回类型设置为evolve
,我会在模式匹配中得到编译器错误,而在模式匹配中出现类似Created
的错误。Registered
AccountDebited
This expression was expected to have type 'Account' but here has type 'RegisteredAccount'
我该如何解决这个问题?
解决方案
我认为您的代码中的问题是该evolve
函数试图返回RegisteredAccount
记录类型的值而不是Account
联合类型的值。
我看到您想使用Unregistered
value (of type Account
) 作为初始值,并且您还添加了一个类型注释,指定的返回类型evolve
应该是Account
。我认为这实际上是你想要的。唯一缺少的是您需要使用Registered
union case 将返回的值包装RegisteredAccount
成Account
.
以下类型检查对我来说很好:
let evolve state event: Account =
match event with
| Created accountCreated ->
{ AccountId = accountCreated.AccountId
Owner = accountCreated.Owner
Balance = accountCreated.StartingBalance } |> Registered
| AccountDebited accountDebited ->
match state with
| Registered s ->
{ s with
Balance = s.Balance - accountDebited.Amount } |> Registered
| _ -> failwith "unregistered account can't be debited"
| _ -> failwith "todo: other cases"
我所要做的就是|> Registered
在您返回记录的两个地方添加!
推荐阅读
- reporting-services - 生成 SSRS 报告时出现内存不足异常错误
- xml - 如何在 XSLT 中检查 Parameter 的值为 null
- javascript - JAVA与html的关系
- ios - iPhone上巨大的导航栏
- sql - 消除所有空值并在一条记录中显示所有值
- android - 如何在 Flutter 中安排通知?
- javascript - 如何使用 Angular 2 在传单地图上添加搜索控件?
- python - 如何在不使用 Python 重塑的情况下更改矩阵的维度
- excel - VBA - 一次清除数千个单元格
- stack-overflow - 调用netsuite restlet时如何修复超时执行异常