如何复制受歧视的工会案例值?

时间:2016-07-25 15:34:35

标签: f#

如何复制受歧视的工会案例值?

以下代码有一些重复:

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 })

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 })