F # - Associazione di una funzione al tipo di oggetto corrispondente

2

Diciamo che sto programmando un gioco di scacchi. A un certo punto devo controllare, quali mosse sono valide per un dato pezzo. Quale sarebbe il modo corretto di selezionare la corretta funzione di ricerca del percorso per un dato brano (re, regina, ecc.)?

Ho trovato tre diversi approcci:

  1. Memorizza il metodo di definizione del percorso (insieme agli altri dati) all'interno di un record (simile al modello di strategia; troppo orientato agli oggetti?)
  2. Crea un PieceType Unione discriminata con tutti i tipi di pezzi e memorizza un valore di questo tipo nel record. Seleziona la corretta funzione di path-path tramite la corrispondenza del pattern
  3. Crea un% record di tipo% co_de che memorizza i dati e un PieceData DU, in cui tutti i casi rappresentano tipi di pezzi diversi e sono di tipo Piece . La corrispondenza del modello viene anche utilizzata per selezionare la funzione corretta.

Ecco alcuni esempi di codice, che dimostrano i diversi approcci:

// The piece "constructor" is private as to only allow creating pieces via
// the provided construct functions for each piece type
type Piece = private { Position:Position; Pathfinder:Position->Board->Position list }

let kingPathfinder position board =
    // Check and return all possible targets for a king

let createKing position =
    { Position=position; Pathfinder=kingPathfinder }

let getPossibleTargets { Position=position; Pathfinder=pathfinder } board =
    pathfinder position board


    ####    ####    ####


type PieceType =
    | King
    | ...

type Piece = { Position:Position; PieceType:PieceType }

let kingPathfinder position board =
    // Check and return all possible targets for a king

let createKing position =
    { Position=position; PieceType=King }

let getPossibleTargets { Position=position; PieceType=pieceType } board =
    match pieceType with
        | King -> kingPathfinder position board
        | ...


    ####    ####    ####


type PieceData = { Position:Position }

type Piece =
    | King of PieceData
    | ...

let kingPathfinder position board =
    // Check and return all possible targets for a king

let createKing position =
    King { Position=position }

let getPossibleTargets piece board =
    match piece with
        | King { Position:position } ->
            kingPathfinder position board

La mia domanda ora è: quale di questi tre approcci è preferito nella programmazione funzionale? O c'è un altro modo migliore?

    
posta Benjamin Rickels 18.12.2016 - 15:33
fonte

1 risposta

2

Il secondo approccio è il migliore.

Il primo approccio ammette dati non validi, ad esempio puoi mettere qualsiasi funzione al posto di PawnData.Pathfinder , e non c'è modo di far valere che è valida.

Il terzo approccio è generalmente ok, ma in questo caso specifico è un po 'dispendioso, perché tutti i casi del DU hanno dati identici.

Il secondo approccio è quello giusto per questo particolare problema.

Inoltre, termini un po 'confusi. La parola "pedina" significa un tipo specifico di pezzo degli scacchi - quello di cui ci sono otto. Dire "pedone del tipo King" è come dire "vescovo del re tipo". Il termine corretto per questo è "pezzo":

type PieceType =
   | King
   ...
    
risposta data 18.12.2016 - 15:48
fonte

Leggi altre domande sui tag