2016-08-03 126 views
0

如何爲List.filter包含多個參數?如何爲List.filter包含多個參數?

我需要添加一些參數到一個函數,作爲過濾列表的謂詞。

在F#中,List.filter只接受一個參數。不過,我需要爲我的謂詞添加多個參數才能工作。

以我爲例,我需要添加sourceXsourceY作爲參數:

let jumpOptions space = 
    match space with 
    | Allocated p -> match p with 
        | Red (ch,xy) -> xy = (sourceX + 1, sourceY - 1) || 
             xy = (sourceX - 1, sourceY - 1) 

        | Black (ch,xy) -> xy = (sourceX + 1, sourceY + 1) || 
             xy = (sourceX - 1, sourceY + 1) 
    | _ -> false 

let jumpsForSoldier piece positions = 
    match piece with 
    | Black (ch,pos) -> positions |> List.filter jumpOptions 
    | Red (ch,pos) -> positions |> List.filter jumpOptions 

最後,我要保持我的列表純內的元素。因此,我不想將我列表中的每個元素與其他值進行綁定,以滿足過濾器功能。

任何指導?

附錄:

open NUnit.Framework 
open FsUnit 

(* Types *) 
type Black = BlackKing | BlackSoldier 
type Red = RedKing | RedSoldier 

type Coordinate = int * int 

type Piece = 
    | Black of Black * Coordinate 
    | Red of Red * Coordinate 

type Space = 
    | Allocated of Piece 
    | Available of Coordinate 

type Status = 
    | BlacksTurn | RedsTurn 
    | BlackWins | RedWins 

(* Private *) 
let private black coordinate = Allocated (Black (BlackSoldier , coordinate)) 
let private red coordinate = Allocated (Red (RedSoldier , coordinate)) 

let private yDirection = function 
    | Black _ -> -1 
    | Red _ -> 1 

let private toAvailable = function 
    | Available pos -> true 
    | _    -> false 

let available positions = positions |> List.filter toAvailable 

let private availableSelection = function 
    | Available pos -> Some pos 
    | Allocated _ -> None 

let private availablePositions positions = 
    positions |> List.filter toAvailable 
       |> List.choose availableSelection 

let private allocatedSelection = function 
    | Allocated p -> match p with 
        | Red (ch,xy) -> Some xy 
        | Black (ch,xy) -> Some xy 
    | _ -> None 

let private allocatedPositions positions = 
    positions |> List.filter toAvailable 
       |> List.choose allocatedSelection 

let private getCoordinate = function 
    | Available xy -> Some xy 
    | _   -> None 

let coordinateOf = function 
    | Black (checker , pos) -> pos 
    | Red (checker , pos) -> pos 

let jumpOptions space = 
    match space with 
    | Allocated p -> match p with 
        | Red (ch,xy) -> let sourceX, sourceY = coordinateOf source 
             xy = (sourceX + 1, sourceY - 1) || 
             xy = (sourceX - 1, sourceY - 1) 

        | Black (ch,xy) -> let sourceX, sourceY = coordinateOf p 
             xy = (sourceX + 1, sourceY + 1) || 
             xy = (sourceX - 1, sourceY + 1) 
    | _ -> false 

let jumpsForSoldier piece positions = 
    match piece with 
    | Black (ch,pos) -> positions |> List.filter jumpOptions 
    | Red (ch,pos) -> positions |> List.filter jumpOptions 

let private isKing piece = 
    match piece with 
    | Black (checker , _) -> match checker with 
          | BlackSoldier -> false 
          | BlackKing -> true 

    | Red (checker , _) -> match checker with 
          | RedSoldier -> false 
          | RedKing  -> true 
(* Public *) 
let startGame() = 
    [ red (0,0); red (2,0); red (4,0); red (6,0) 
     red (1,1); red (3,1); red (5,1); red (7,1) 
     red (0,2); red (2,2); red (4,2); red (6,2) 

     Available (1,3); Available (3,3); Available (5,3); Available (7,3) 
     Available (0,4); Available (2,4); Available (4,4); Available (6,4) 

     black (1,5); black (3,5); black (5,5); black (7,5) 
     black (0,6); black (2,6); black (4,6); black (6,6) 
     black (1,7); black (3,7); black (5,7); black (7,7) ] , BlacksTurn 

let optionsFor piece positions = 

    let sourceX , sourceY = coordinateOf piece 


    let optionsForSoldier = 
     (fun pos -> pos = ((sourceX - 1) , (sourceY + (piece |> yDirection))) || 
        pos = ((sourceX + 1) , (sourceY + (piece |> yDirection)))) 

    let optionsForKing = 
     (fun pos -> pos = ((sourceX - 1) , (sourceY + 1)) || 
        pos = ((sourceX + 1) , (sourceY + 1)) || 
        pos = ((sourceX - 1) , (sourceY - 1)) || 
        pos = ((sourceX + 1) , (sourceY - 1))) 

    match piece |> isKing with 
    | false -> positions |> availablePositions 
         |> List.filter optionsForSoldier 


    | true -> positions |> availablePositions 
         |> List.filter optionsForKing 

let move piece destination positions = 

    let rec movePiece positions destinationXY = 
     let foundPiece = positions |> List.filter (fun space -> space = Allocated piece) 
            |> List.head 
     match foundPiece with 
     | Allocated (Black (ch, xy)) -> (positions |> List.filter (fun space -> space <> Allocated (Black (ch, xy))) 
                |> List.filter (fun space -> space <> destination)) 
                @ [Available (xy) ; (Allocated (Black (ch, destinationXY)))] 

     | Allocated (Red (ch, xy)) -> (positions |> List.filter (fun space -> space <> Allocated (Red (ch, xy))) 
                |> List.filter (fun space -> space <> destination)) 
                @ [Available (xy) ; (Allocated (Red (ch, destinationXY)))] 
     | _ -> positions 

    let options = optionsFor piece positions 
    let canMoveTo = (fun target -> options |> List.exists (fun xy -> xy = target)) 

    match getCoordinate destination with 
    | Some target -> match canMoveTo target with 
        | true -> movePiece positions target 
        | false -> positions 
    | None -> positions 

(* Tests *) 
[<Test>] 
let ``get jump options for red soldier``() = 
    // Setup 
    let redPiece = Red (RedSoldier , (0,2)) 
    let blackPiece = Black (BlackSoldier , (1,3)) 
    let positions = [Allocated redPiece; Available (2,2); Available (4,2); Available (6,2)     
        Allocated blackPiece; Available (3,3); Available (5,3); Available (7,3) 
        Available (0,4);  Available (2,4);  Available (4,4); Available (6,4)] 
    // Test 
    positions |> jumpsForSoldier redPiece 
       |> should equal [Allocated blackPiece] 

回答

5

你可以有很多參數,只要你想,那麼函數部分適用於所有的人,但一個,並將結果傳遞給List.filter

let jumpOptions sourceX sourceY space = ... 

... 
    positions |> List.filter (jumpOptions 5 42) 

閱讀更多部分申請here

1

你可以使用模式匹配提取所需的信息,並使用部分應用程序(代碼TQBF意見後編輯)

let jumpOptions (sourceX, sourceY) = function 
    Allocated (Red (_, (x, y)) as p) 
| Allocated (Black (_, (x, y)) as p) when abs (sourceX - x) = 1 
    -> y = sourceY - yDirection p 
| _ -> false 

let jumpsForSoldier = function 
    Red (_, pos) 
| Black (_, pos) -> List.filter (jumpOptions pos) 
+0

此代碼不會因爲一個無與倫比的括號的編譯和'when'子句中一個不允許的地方。我假設刪除'when'會破壞它的邏輯。 – TheQuickBrownFox

+0

@TheQuickBrownFox哎呀錯過了那一個。不確定要了解'when'部分;如果它與缺少的圓括號有關或者意味着更多 – Sehnsucht

+0

問題是,每個模式只能有一個「when」,而兩個「Allocated」行確實會形成一個更大的模式,其中包含兩個與「|」組合的子模式。 '(OR)。 – TheQuickBrownFox

相關問題