2016-07-29 81 views
1

如何以參數值的形式返回參數?如何以參數值的形式返回參數?

我有以下功能:

let jumpBlack ((blackChecker:BlackChecker),(blackCheckers:BlackChecker list)) (redPiece:RedPiece) = 

    let yIncrementValue = -1 
    let minY = 0 

    match redPiece with 
    | RedPiece.RedChecker rc -> 
     let position = rc.Position |> jump blackChecker.Position yIncrementValue 
     match position with 
     | pos when pos = rc.Position -> RedPiece.RedChecker { rc with Position= position }, blackCheckers 
     | pos when pos.Y = minY  -> RedPiece.RedKing { RedKing.Position=position }, blackCheckers |> remove blackChecker 
     | _ ->       RedPiece.RedChecker { rc with Position= position }, blackCheckers |> remove blackChecker 

    | RedPiece.RedKing rk -> 
     let position = rk.Position |> jump blackChecker.Position yIncrementValue 
     match position with 
     | pos when pos = rk.Position -> RedPiece.RedKing { rk with Position= position }, blackCheckers 
     | pos when pos.Y = minY  -> RedPiece.RedKing { Position=position }, blackCheckers |> remove blackChecker 
     | _       -> RedPiece.RedKing { rk with Position= position }, blackCheckers |> remove blackChecker 

具體來說,我想上面的這部分功能重構爲一個函數:

match redPiece with 
| RedPiece.RedChecker rc -> 
    let position = rc.Position |> jump blackChecker.Position yIncrementValue 
    match position with 
    | pos when pos = rc.Position -> RedPiece.RedChecker { rc with Position= position }, blackCheckers 
    | pos when pos.Y = minY  -> RedPiece.RedKing { RedKing.Position=position }, blackCheckers |> remove blackChecker 
    | _ ->       RedPiece.RedChecker { rc with Position= position }, blackCheckers |> remove blackChecker 

| RedPiece.RedKing rk -> 
    let position = rk.Position |> jump blackChecker.Position yIncrementValue 
    match position with 
    | pos when pos = rk.Position -> RedPiece.RedKing { rk with Position= position }, blackCheckers 
    | pos when pos.Y = minY  -> RedPiece.RedKing { Position=position }, blackCheckers |> remove blackChecker 
    | _       -> RedPiece.RedKing { rk with Position= position }, blackCheckers |> remove blackChecker 

如何重構上面重複的代碼?

我卡在如何去除重複,仍然會返回兩種不同類型的工會(即紅色方格和紅國王)

域:

(* Types *) 
type North = NorthEast | NorthWest 
type South = SouthEast | SouthWest 

type Direction = 
    | NorthEast 
    | NorthWest 
    | SouthEast 
    | SouthWest 

type Position =  { X:int; Y:int } 

type BlackChecker = { Position:Position } 
type RedChecker = { Position:Position } 
type BlackKing = { Position:Position } 
type RedKing =  { Position:Position } 

type Checker = 
    | BlackChecker of BlackChecker 
    | RedChecker of RedChecker 
    | BlackKing of BlackKing 
    | RedKing  of RedKing 

type King = 
    | BlackKing of BlackKing 
    | RedKing of RedKing 

type RedPiece = 
    | RedChecker of RedChecker 
    | RedKing of RedKing 

(* Functions *) 
let rec remove item list = list |> List.filter (fun x -> x <> item) 

let setRowPosition y1 y2 y3 index = 
    match index with 
    | x when x < 4 -> { X=x; Y=y1 } 
    | x when x < 8 -> { X=x-4; Y=y2 } 
    | _   -> { X=index-8; Y=y3 } 

let initializeBlack() = 
    let setPosition index = 
     index |> setRowPosition 7 6 5 

    let blackCheckers = List.init 12 setPosition |> List.map (fun pos -> { BlackChecker.Position= { X=pos.X; Y=pos.Y } }) 
    blackCheckers 

let initializeRed() = 
    let setPosition index = 
     index |> setRowPosition 0 1 2 

    let redCheckers = List.init 12 setPosition |> List.map (fun pos -> { RedChecker.Position= { X=pos.X; Y=pos.Y } }) 
    redCheckers 

let set (x, y) positions (position:Position) = 
    match not (positions |> List.exists (fun pos -> pos = { X=x; Y=y })) with 
    | true -> { X=x; Y=y } 
    | false -> position 

let moveBlack direction positions (checker:BlackChecker) = 
    let position = checker.Position 

    match direction with 
    | North.NorthEast -> { BlackChecker.Position= (positions, position) ||> set ((position.X + 1), (position.Y + 1)) } 
    | North.NorthWest -> { BlackChecker.Position= (positions, position) ||> set ((position.X - 1), (position.Y + 1)) } 

let moveRed direction positions (checker:RedChecker) = 
    let position = checker.Position 

    match direction with 
    | South.SouthEast -> { RedChecker.Position= (positions, position) ||> set ((position.X + 1), (position.Y - 1)) } 
    | South.SouthWest -> { RedChecker.Position= (positions, position) ||> set ((position.X - 1), (position.Y - 1)) } 

let moveKing direction positions (king:King) = 

    let position = match king with 
        | King.BlackKing bk -> bk.Position 
        | King.RedKing rk -> rk.Position 

    let result = match direction with 
       | NorthEast -> (positions, position) ||> set ((position.X + 1), (position.Y + 1)) 
       | NorthWest -> (positions, position) ||> set ((position.X - 1), (position.Y + 1)) 
       | SouthEast -> (positions, position) ||> set ((position.X + 1), (position.Y - 1)) 
       | SouthWest -> (positions, position) ||> set ((position.X - 1), (position.Y - 1)) 

    match king with 
    | King.BlackKing _ -> King.BlackKing { BlackKing.Position= result } 
    | King.RedKing _ -> King.RedKing { RedKing.Position= result } 

let jump target yDirection source = 
    let updateX value = { X=target.X + value 
          Y=target.Y + yDirection } 
    match source with 
    | position when position.Y + yDirection = target.Y && 
        position.X + 1 = target.X -> updateX 1 

    | position when position.Y + yDirection = target.Y && 
        position.X - 1 = target.X -> updateX -1 
    | _ -> source 

let jumpRed ((redChecker:RedChecker), (redCheckers:RedChecker list)) (blackChecker:BlackChecker) = 

    let yIncrementValue = 1 
    let maxY = 7 
    let position = blackChecker.Position |> jump redChecker.Position yIncrementValue 

    match position with 
    | pos when pos = blackChecker.Position -> BlackChecker { blackChecker with Position= position }, redCheckers 
    | pos when pos.Y = maxY    -> Checker.BlackKing { BlackKing.Position=position }, redCheckers |> remove redChecker 
    | _ -> BlackChecker { blackChecker with Position= position }, redCheckers |> remove redChecker 

let jumpBlack ((blackChecker:BlackChecker),(blackCheckers:BlackChecker list)) (redPiece:RedPiece) = 

    let yIncrementValue = -1 
    let minY = 0 

    match redPiece with 
    | RedPiece.RedChecker rc -> 
     let position = rc.Position |> jump blackChecker.Position yIncrementValue 
     match position with 
     | pos when pos = rc.Position -> RedPiece.RedChecker { rc with Position= position }, blackCheckers 
     | pos when pos.Y = minY  -> RedPiece.RedKing { RedKing.Position=position }, blackCheckers |> remove blackChecker 
     | _ ->       RedPiece.RedChecker { rc with Position= position }, blackCheckers |> remove blackChecker 

    | RedPiece.RedKing rk -> 
     let position = rk.Position |> jump blackChecker.Position yIncrementValue 
     match position with 
     | pos when pos = rk.Position -> RedPiece.RedKing { rk with Position= position }, blackCheckers 
     | pos when pos.Y = minY  -> RedPiece.RedKing { Position=position }, blackCheckers |> remove blackChecker 
     | _       -> RedPiece.RedKing { rk with Position= position }, blackCheckers |> remove blackChecker 

測試:

[<Test> 
let ``red king jumps checker``() = 
    let blackChecker = { BlackChecker.Position= { X=1 ; Y=1 } } 
    let target = (blackChecker, [blackChecker]) 

    RedKing { RedKing.Position= { X=0 ; Y=2 } } |> jumpBlack target 
               |> fst 
               |> should equal (RedPiece.RedKing { RedKing.Position= { X=2 ; Y=0 } }) 

[<Test>] 
let ``black checker removed after being jumped``() = 
    let target = { BlackChecker.Position= { X=1 ; Y=1 } }, [] 
    RedChecker { RedChecker.Position= { X=2 ; Y=2 } } |> jumpBlack target 
                 |> snd 
                 |> should equal [] 
[<Test>] 
let ``red checker jumps black checker southeast``() = 
    let blackChecker = { BlackChecker.Position= { X=3 ; Y=2 } } 
    let target = blackChecker, [blackChecker] 

    RedChecker { RedChecker.Position= { X=2 ; Y=3 } } |> jumpBlack target 
                 |> fst 
                 |> should equal (RedChecker { RedChecker.Position= { X=4 ; Y=1 } }) 
+0

是否可以壓縮代碼以專注於實際問題?你不能返回一個元組,或者將它包裝在Some中? – s952163

+0

轉到[代碼評論](http://codereview.stackexchange.com/) – s952163

+0

代碼是函數jumpBlack。域部分和測試部分充當上下文信息。 –

回答

2

在你想重構的代碼中,seeme d只有兩個地方,代碼的兩部分做了不同的事情 - 一個是模式匹配(其中一個尋找RedChecker,另一個尋找RedKing),另一個部分是模式的第一行和第三行的主體匹配(其中一個返回RedChecker,另一個返回RedKing)。

的代碼也可以運行在不同的類型,但這些都是同一類型:

type BlackChecker = { Position:Position } 
type RedChecker = { Position:Position } 
type BlackKing = { Position:Position } 
type RedKing =  { Position:Position } 

提取共同部分將是一個容易得多,如果你只是使用相同類型的所有這些:

type Piece = { Position:Position } 
type BlackChecker = Piece 
type RedChecker = Piece 
type BlackKing = Piece 
type RedKing = Piece 

所以,你需要兩樣東西參數化的代碼 - 他們都可以表示爲以下類型的功能:

detector  : Checker -> Piece option 
wrapper  : Piece -> Checker 

這裏的關鍵訣竅是,這兩個函數的行爲像識別聯合的情況下 - 第一個使用DU的情況下表現爲模式匹配和第二個行爲類似於DU殼體的構造。

現在,您可以提取通用的功能到是這樣的:

match detector redPiece with 
| Some rk -> 
    let position = rk.Position |> jump blackChecker.Position yIncrementValue 
    match position with 
    | pos when pos = rk.Position -> wrapper { rk with Position= position }, blackCheckers 
    | pos when pos.Y = minY  -> RedPiece.RedKing { Position=position }, blackCheckers |> remove blackChecker 
    | _       -> wrapper { rk with Position= position }, blackCheckers |> remove blackChecker 

| None -> // Handle the case when it is not the piece we are interested in 

我沒有測試過的一切,但希望這至少說明了思想路線,您可以按照從兩個提取通用的功能部分。這就是說,我不會太擔心重構代碼 - 如果你重複類似的事情只是兩次,我覺得這是通常更容易只是爲了保持兩個副本...

+0

感謝Tomas。我會醃你的指導,讓它沉入水中。 –

2

好吧,你的模型是非常複雜...我作了如下簡化:

type Position = { X:int; Y:int } 

type Color = 
    | Red 
    | Black 

type PieceType = 
    | King 
    | Checker 

type Piece = Color*PieceType*Position 

然後翻譯您jumpBlack功能我得到:

let jumpBlack ((blackChecker:Piece),(blackCheckers:Piece list)) (redPiece:Piece) = 

    let yIncrementValue = -1 
    let minY = 0 

    match redPiece, blackChecker with 
    | (Red, Checker, position), (_, _, blackCheckerPosition) -> 
     let newposition = position |> jump blackCheckerPosition yIncrementValue 
     match newposition with 
     | pos when pos = position -> (Red, Checker, pos), blackCheckers 
     | pos when pos.Y = minY  -> (Red, King, pos) , blackCheckers |> remove blackChecker 
     | pos ->       (Red, Checker, pos), blackCheckers |> remove blackChecker 
    | (Red, King, position), (_, _, blackCheckerPosition) -> 
     let newposition = position |> jump blackCheckerPosition yIncrementValue 
     match newposition with 
     | pos when pos = position -> (Red, King, pos), blackCheckers 
     | pos when pos.Y = minY  -> (Red, King, pos), blackCheckers |> remove blackChecker 
     | pos       -> (Red, King, pos), blackCheckers |> remove blackChecker 
    | _ -> failwith "Invalid" //Deal with Black pieces here! 

但現在,它真的很容易,因爲我們看到重構代碼,如果pos不等於minY價值,它保持不變PieceType,但如果它達到minY它總是變成King

let jumpBlackNew ((blackChecker:Piece),(blackCheckers:Piece list)) (redPiece:Piece) = 

    let yIncrementValue = -1 
    let minY = 0 

    match redPiece, blackChecker with 
    | (Red, pieceType, position), (_, _, blackCheckerPosition) -> 
     let newposition = position |> jump blackCheckerPosition yIncrementValue 
     match newposition with 
     | pos when pos = position -> (Red, pieceType, pos), blackCheckers 
     | pos when pos.Y = minY  -> (Red, King, pos) , blackCheckers |> remove blackChecker 
     | pos ->      (Red, pieceType, pos), blackCheckers |> remove blackChecker 
    | _ -> failwith "Invalid" //Deal with Black pieces here! 

這也使你更容易在黑色和紅色跳棋中跳躍。