Qual è il modo idiomatico in f # per esprimere una sequenza di istruzioni if con condizioni di sovrapposizione

1

Diciamo che ho ottenuto il codice in questo modo:

if(conditionA)
    do something
if(conditionA && conditionB)
    do something more

Ovviamente, potrei annidare i if (anche se in condizioni più complicate questo non è leggibile per me) come di seguito:

if(conditionA)
    do something
    if(conditionB)
        do something more

Come posso scrivere un codice simile in f # in modo idiomatico. Presumo che l'affermazione non sia considerata idiomatica nella programmazione funzionale (sbaglio?)

Potrei scrivere due espressioni di corrispondenza successive o un'espressione di corrispondenza annidata per simulare il codice precedente, ma farlo mi sembra abbastanza brutto.

    
posta Grzegorz Sławecki 08.01.2015 - 23:24
fonte

2 risposte

3

Non c'è niente di sbagliato nell'usare if-then-else in F #. È così idiomatico come le cose possono ottenere. La maggior parte delle persone evidenzia le espressioni match quando si parla di F #, quindi potrebbe sembrare che ifs sia scoraggiato, ma non è proprio il modo giusto di pensare alle cose.

È vero che le espressioni match sono potenti. Non ci vuole molto per trarre vantaggio dal loro utilizzo anziché ifs quando:

  • puoi usare decostruzione negli schemi,
  • o vuoi abbinare una tupla di valori,
  • o hai più casi di un binario vero / falso e vuoi gestirli senza costruire torri if-else.

Detto questo usando il costrutto sotto dovrebbe essere chiamato in una revisione del codice (e giustamente - questo avrebbe dovuto essere un if):

match cond with
| true -> ...
| false -> ...

È approssimativamente sullo stesso livello dell'odore di codice della struttura temuta che a volte potresti vedere nel codice lang male in stile c:

/// this is bad, don't do this at home (just return cond).
if (cond) {
    return true;
} else {
    return false;
}

Non vedo un problema nel secondo frammento con if annidati. Detto questo, potrebbero esserci soluzioni migliori, ma è difficile suggerirne una quando si parla di do somethings e conditionBs .

    
risposta data 09.01.2015 - 00:02
fonte
3

F # è un linguaggio orientato all'espressione quindi, come sottolinea Karl Bielefeldt, avere if/else di espressioni che non restituiscono alcun valore è già unidiomatico.

Un altro aspetto del codice funzionale idiomatico è quello di rendere esplicito che tutti i rami possibili sono stati affrontati. Questo è uno dei motivi per cui il pattern matching con i sindacati discriminati è così popolare - il compilatore ti avviserà se hai dimenticato un caso.

Il if/else di per sé è perfettamente accettabile, ma sembra che tu stia facendo qualcosa di un po 'più complicato, quando hai condizioni complesse come questa. Se guardassi questo codice, chiederei cosa succede se not conditionA contiene? Il codice non lo rende chiaro.

Se questo insieme di condizioni nidificate si verifica frequentemente, o è un pezzo di codice critico che richiede chiarezza, allora personalmente sostituirò le varie condizioni con un'unione discriminata per rendere evidente al lettore cosa sta succedendo.

type Keypress = 
    | AOnly 
    | AAndB
    | NeitherANorB

(Ovviamente i nomi sono brutti - dovresti rinominare i casi in base alle tue esigenze!)

Quindi crea una funzione di traduttore che trasforma l'input in uno dei casi Keypress :

let inputToKeypress input = 
    if conditionA then
        if conditionB then AAndB else AOnly 
    else
        NeitherANorB

Infine, il tuo codice principale può eseguire lo schema in modo ovvio.

let mainCode keypress = 
   match keypress with          
   | AOnly -> do something
   | AAndB -> do something; do something more;
   | NeitherANorB -> () // ignore

Un ulteriore vantaggio di questo approccio è che se aggiungi o rimuovi casi nel tuo tipo di unione, il tuo codice non riuscirà a compilare. Non così con espressioni% co_de nidificate.

    
risposta data 11.01.2015 - 23:58
fonte

Leggi altre domande sui tag