2014-11-01 15 views
5

Sto lavorando su un codice per un gioco di carte:Sta scrivendo le funzioni di supporto per lo stile di passaggio di stato idiomatico in Haskell?

splitCards_ (x:xs) (a,b,c) | isGold x = splitCards xs (a:x,b,c) 
          | isAction x = splitCards xs (a,b:x,c) 
          | isVP x  = splitCards xs (a,b,c:x) 
splitCards_ [] (a,b,c) = (a,b,c) 

splitCards xs = splitCards_ xs ([],[],[]) 

In sostanza, prendendo un elenco di schede, e dividendolo in tre diverse liste a seconda del tipo di scheda. splitCards_ rappresenta gli aggiornamenti di stato aggiornando in modo ricorsivo i suoi parametri, quindi splitCards (la funzione effettiva) viene utilizzato per avviare sempre il calcolo con i tre elenchi di tipi specifici di schede vuote.

Credo che questo si chiami stile di passaggio dello stato, e sono abbastanza sicuro che sia perfettamente idiomatico, ma sono più preoccupato del fatto che devo definire una funzione di supporto splitCards_ per far funzionare questo modo che voglio La creazione di funzioni di supporto come questo Haskell idiomatico? C'è un modo più pulito per scrivere questo? Esistono convenzioni di denominazione preferibili semplicemente mettendo un trattino basso alla fine del nome della funzione di aiuto?

risposta

8

Sì, questo è uno stile perfettamente idiomatico. È un modo classico per rendere ricorsiva una funzione di coda. (Anche se è meno importante e leggermente più sfumato in Haskell).

Inoltre, le funzioni di supporto sono sicuramente buone e una parte fondamentale di molti modelli comuni. Se senti che qualcosa è più naturale da scomporre, fallo! A meno che non sia portato all'estremo, aiuta la leggibilità.

Il suggerimento principale che ho è mettere la funzione di supporto in una clausola where. In questo modo, sarà visibile solo nell'ambito della funzione principale che chiarisce che è solo un aiuto. Il nome che assegni alla funzione di aiuto è meno importante; splitCards_ va bene, ma splitCards' (pronuncia "splitCards prime") e go (un nome generico per le funzioni di supporto) sarebbe più comune. Quindi mi sento di riscrivere il codice qualcosa di simile:

splitCards xs = go xs ([],[],[]) 
    where go (x:xs) (a, b, c) | isGold x = go xs (a:x,b,c) 
          | isAction x = go xs (a,b:x,c) 
          | isVP x  = go xs (a,b,c:x) 
     go [] (a, b, c) = (a, b, c) 

Nota che questi sono i cambiamenti a quello che è appena cosmetici che stavi facendo è fondamentalmente suono.

Le due opzioni di denominazione (go vs splitCards') sono solo una questione di preferenza.

Personalmente mi piace il go perché, una volta abituato alla convenzione, segnala chiaramente che qualcosa è solo una funzione di supporto. In un certo senso, go è quasi più simile alla sintassi di una sua funzione; il suo significato è puramente subordinato alla funzione splitCards.

Altri non mi piace go perché è un po 'criptico e un po' arbitrario. Potrebbe anche rendere meno chiara la struttura ricorsiva del tuo codice perché stai ricorsivamente su go e non sulla funzione stessa.

Vai per quello che pensi sia meglio.

3

Non ho niente da aggiungere a @ risposta di Tikhon, tranne che nel caso specifico è possibile utilizzare la funzione di partition da Data.List:

splitCards xs = 
    let (as,bs) = partition isGold xs 
     (cs,ds) = partition isAction bs 
    in (as,cs,ds) -- (golds, actions, others) 

Grazie alla valutazione pigra dovrebbe avere essenzialmente le stesse prestazioni di una mano versione artigianale.

1

Nel caso generale, il codice come vostro è unidirezionale, soprattutto se ripulito un po 'come suggerito da @Tikhon. Nel caso specifico, il tuo schema di ricorsione sembra essere una piega a sinistra, quindi viene solitamente reso esplicito nel codice. Sulla base @ codice di Tikhon:

splitCards xs = foldl' separate ([],[],[]) xs 
    where separate (a, b, c) x | isGold x = (a:x,b,c) 
          | isAction x = (a,b:x,c) 
          | isVP x  = (a,b,c:x) 

La prima riga può anche essere in eta terzi (non molto bisogno in questo caso, secondo me, ma ...)

splitCards = foldl' separate ([],[],[]) 
    where ... 
Problemi correlati