2016-07-29 80 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! 

这也使你更容易在黑色和红色跳棋中跳跃。