2015-05-30 8 views
5

Questa è una domanda di stile di codifica piuttosto che una tecnica.Denominazione dei conflitti tra i valori dei campi e l'ambito locale in Haskell

Ho riscontrato spesso un problema in cui utilizzo la sintassi del record (meno che ottimale) di haskell (o gli obiettivi, il problema finisce lo stesso) per creare un tipo data. Finisco con le funzioni di accesso al campo che prendono il nome dai miei campi. Essendo un programmatore coscienzioso, cerco di rendere significativi i miei nomi dei campi dei record.

A un certo punto più tardi ho bisogno di ottenere un campo dal mio tipo e mantenere il suo valore in una variabile locale. Questo è spesso fatto all'interno di una StateMonad in un blocco do. La domanda è che cosa chiamo la variabile locale. Il nome più ovvio è già preso come accesso al campo. Trovo me stesso usando le abbreviazioni che tendono a rendere il mio codice meno leggibile.

Esiste una convenzione di codifica Haskell che risolva questo problema?

Esempio

data Qaax = Qaax { 
     foo :: SomeFoo 
    , bar :: SomeBar 
    , ... 
    } 

baz :: (MonadState Qaax m) => (...) -> m() 
baz (...) = do 
    f <- gets foo -- I'd really like to use something more descriptive then 
       -- `f` but `foo` is already taken. 
    ... 
    return() 

risposta

3

L'aggiunta di "come suffisso è una convenzione stabilita per la creazione di nomi distinti ma correlati. Un esempio chiave è foldl e foldl'.

Nei nomi esportati come foldl' è di solito una buona idea proporre un tema coerente per ciò che significa "per la libreria" (spesso è "versione più rigida di", come in foldl'). Ma nei nomi locali puoi essere molto più libero di usarlo semplicemente "un'altra cosa strettamente correlata che vorrei avere lo stesso nome di".

Lo svantaggio è che non è molto distinto, quindi può danneggiare la leggibilità; soprattutto se è necessario fare riferimento a entrambe le versioni. E quando ti ritrovi ad aver bisogno di foo''' dovresti probabilmente pensare a un diverso schema di denominazione!

2

L'estensione NamedFieldPuns può aiutare con questo. Quando pattern-matching su un disco, si lega una variabile con lo stesso nome di un campo del record:

{-# LANGUAGE NamedFieldPuns #-} 

baz :: (MonadState Qaax m) => m() 
baz = do 
    Qaax {foo} <- get 
    return() 

Un possibile problema è che la funzione di accesso è ombreggiato per il resto del blocco do.