如何复制受歧视的工会案例值?
以下代码有一些重复:
let move (direction:Direction) (checker:Checker) =
match checker with
| Red xy -> Red { xy with X=2; Y=2 }
| Black xy -> Black { xy with X=2; Y=2 }
具体来说,我不想仅仅为了设置其记录值来指定检查器的类型。因此,如果检查员是红色或黑色,我不在乎。我想复制检查器案例值并更新其位置。
我宁愿做这样的事情:
let move (direction:Direction) (checker:Checker) =
match checker with
| _ xy -> _ { xy with X=2; Y=2 }
这是我的测试:
[<Test>]
let ``move checker``() =
Black { X=1; Y=1 } |> move NorthEast
|> should equal (Black { X=2; Y=2 })
附录
module Test3
open NUnit.Framework
open FsUnit
type Position = { X:int; Y:int }
type Checker = | Red of Position | Black of Position
type Direction =
| NorthEast
| NorthWest
| SouthEast
| SouthWest
(* Functions *)
let move (direction:Direction) (checker:Checker) =
match checker with
| Red xy -> Red { xy with X=2; Y=2 }
| Black xy -> Black { xy with X=2; Y=2 }
[<Test>]
let ``move checker``() =
Black { X=1; Y=1 } |> move NorthEast
|> should equal (Black { X=2; Y=2 })
答案 0 :(得分:6)
你要求的东西不能用F#完成而不需要反思诡计。
这是一个常识解释:联合案例在其下面具有完全相同的数据是非常罕见的。在这种情况下,它可能表明工会案例本身只是一个&#34;标签&#34;用于标记数据,因此应编码&#34;以及&#34;数据,而不是&#34;周围&#34;它。由于这种联合类型是罕见的例外,因此发明语言机制来支持它们是没有意义的。
这种合理化很好地适用于您的具体案例:检查者的颜色是&#34;标签&#34;应该是&#34;旁边&#34;这个位置,而不是&#34;包装&#34;它。如果您将检查器定义为{ pos: Position; color: Color }
,那么您将能够在不触及颜色的情况下更新位置。
答案 1 :(得分:4)
我不确定我是否应该购买&#34;标签应位于该位置旁边而不是包裹它#34;推理。当然,这个例子可能过于简单,但是当你的一些联合案例共享一个你想以透明的方式操作的数据时,它是一个非常有效的场景。
标准FP模式是在类型上具有地图功能。例如,您可以在联合类型上定义一个专门的地图函数,该函数知道如何更新每个案例的位置:
type Checker =
| Orange of Position
| Blue of (Position * DateTime)
| Bacon of bool
member this.MapPosition (f: Position -> Position) =
match this with
| Orange pos -> Orange (f pos)
| Blue (pos, dt) -> Blue (f pos, dt)
| Bacon x -> Bacon x
并像这样使用它:
let move (direction:Direction) (checker:Checker) =
checker.MapPosition(fun _ -> { X=2; Y=2 })