是否有一个简洁的内联表达式来展开单个案例歧视联盟?

时间:2016-03-16 21:03:16

标签: f#

我正在研究F#的基础知识,但我仍然不确定可能的或可用的内容。我认为应该有更好的方法来做到这一点:

我正在查看使用此代码添加类型保护的常见演示场景

type CustomerId = CustomerId of int
type OrderId = OrderId of int

在某些时候,我有需要解包整数的持久性代码:

dbcmd.Execute(CID = ???, OID = ???)

选项A:笨重但有效

dbcmd.Execute(CID = match CustomerId with (CustomerId cid) -> cid, OID = match OrderId with (OrderId oid) -> oid)

选项B源自Concise pattern match on single case discriminated union in F#

中的答案

这需要2行,如果有4或5件事要解开,我开始真的不喜欢距离'在let声明的左侧和右侧之间 - 我可能最终输入无序的内容

let (CustomerId cid, OrderId oid) = (CustomerId, OrderId)
dbcmd.Execute(CID = cid, OrderId = oid)

选项C:如果没有什么比这更好的话,这可能是我更喜欢的。很明显,但比我希望的消耗更多的垂直空间

let (CustomerId cid) = CustomerId
let (OrderId oid) = OrderId
dbcmd.Execute(CID = cid, OrderId = oid)

选项D:这是我希望存在的一种。这实际上并不起作用,因为这是包装的语法,而不是解包,但是你明白了这个想法

dbcmd.Execute(CID = (CustomerId id), OID = (OrderId id))

是否存在类似于选项D的简洁语法?

2 个答案:

答案 0 :(得分:7)

我通常使用其中一种选项,直观地在它们之间进行选择。大多数情况下,我更喜欢选项1,但如果我需要将构造函数设为私有,它就无法工作。

选项1:在参数声明中指定模式

你可以这样做,因为功能参数不一定只是普通的标识符,它们也可以是模式。

let f (CustomerId cid) (OrderId oid) =
  let cmd = ...
  cmd.Execute( cid, oid )

选项2:创建特殊的访问者函数

type CustomerId = CustomerId of int
   with static member toInt (CustomerId id) = id

cmd.Execute( CustomerId.toInt cid, ... )

选项2b:相同,但具有实例成员

type CustomerId = CustomerId of int
   with member this.asInt = match this with (CustomerId id) -> id

cmd.Execute( cid.asInt, ... )

答案 1 :(得分:3)

您也可以在不修改或扩展类型定义的情况下使用lambda:

cid |> fun (CustomerId i) -> i