2016-08-03 20 views
0

List.filterに複数の引数を含めるにはどうすればよいですか?List.filterに複数の引数を含めるにはどうすればよいですか?

リストをフィルタリングするための述語として機能するいくつかのパラメータを関数に追加する必要があります。

F#では、List.filterは引数を1つだけ受け入れます。しかし、私は述語が機能するために複数の引数を追加する必要があります。私の場合は

、私はパラメータとして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

あなたが好きなあなたはその後、部分的にそれらのすべてが、1つに関数を適用し、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'句でコンパイルされません。許可されていない場所。私は 'いつ'がその論理を破るだろうと考えています。 – TheQuickBrownFox

+0

@TheQuickBrownFoxはそれを逃してしまいました。 'when'部分を理解していない。もしそれが欠落している括弧に関連していたり​​、何かを意味しているのであれば、 – Sehnsucht

+0

パターンごとに 'when'を1つだけ持つことができ、2つの' Allocated'行は '| | '(OR)。 – TheQuickBrownFox

関連する問題