2016-07-25 39 views
1

如何複製區分的工會案例值?如何複製區分的工會案例值?

下面的代碼有一些重複:

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

你的數據類型在裏面。如果這是你的用例,你應該將檢查器定義爲'{pos:Position;顏色:顏色}',那麼你可以在不觸摸顏色的情況下更新位置。 –

+0

啊......這很有道理。順便說一下,無論我的設計問題是否可以複製工會案例值? –

回答

6

你要求的東西不能在沒有反射技巧的F#中完成。

這裏一個常識的解釋:這是非常罕見的,工會的情況下面有完全相同的數據。在這種情況下,這可能表明工會案件本身只是用於標記數據的「標籤」,因此應該與數據「並排」編碼,而不是「圍繞」數據。而且由於這種聯合類型是極少數例外情況,所以發明語言機制來支持它們是沒有意義的。

這一合理化適用於您的具體情況很好:格子的顏色是一個「標籤」,應該是「旁邊的」位置,而不是「包裝」它。如果您將檢查器定義爲{ pos: Position; color: Color },則可以在不觸摸顏色的情況下更新位置。

+0

從技術上講,如果我們可以做一個函數(或者活動模式函數),它可以在沒有反射的情況下實現,但是我們沒有反射(我沒有說它應該被完成)。 CheckerCtor |)=功能紅色_ - >紅色|黑_ - > Black'然後可用這樣'讓移動目錄(CheckerCtor構造函數)=構造函數dir'(我們也可以提取使用,如果我們想在每一案件相關的數據,但是這確實令人費解) – Sehnsucht

+0

這是類似(在某種意義上)scrwtp在他的回答中寫下了什麼,我的反對意見也是相似的。 –

+0

肯定的事情;我從不說它應該被使用;只是關於「只做反思」在某種意義上是誤導你的答案 – Sehnsucht

4

我不知道,如果我買的「標籤應該是旁邊的位置,而不是其包裝」的道理。當然,這個例子可能過於簡單,但當你的一些工會案例以透明的方式共享一段你想要操作的數據時,這是一個非常有效的場景。

標準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 }) 
+0

這不是斯科特所要求的。他想要一個神奇的語言功能來做到這一點,而這並不存在。當然,如果你願意把所有的醜陋都隱藏在效用函數中,你可以做任何事情。但是醜陋並沒有消失,只是隱藏起來。 –

+0

另外,請注意您的示例在每種情況下實際上並不具有完全相同的數據,因此這不是我描述的「標記」情況。 –

+0

@FyodorSoikin:「魔法語言功能」和「必須複製粘貼代碼中的所有內容」之間有很多不同的內容。 OP尋找的是一種減少代碼重複的方法,並且我提出了針對這種問題的一種通用的,結構化的方法。我在這裏看不到醜陋。 – scrwtp