2013-10-04 19 views
5

Sto controllando che non ci sia una certa pratica corrente con Template-Haskell/some fanciness lenti a che fare con il semplice caso di:attuale best-practice per quanto riguarda record di namespacing globale

data Person = Person { 
    name :: String, 
    ... 
} 

data Company = Company { 
    name :: String, 
    ... 
} 

Attualmente sto evitando di inquinare lo spazio dei nomi globale qualificando l'importazione, ma rende l'accesso al record maldestro.

import Person as P 

isFred :: Person -> Bool 
isFred p = (P.name p) == "Fred" 

Non esiste ancora un modo migliore per accedere ai campi dei record?


Sono accettare la risposta di @Emmanuel Touzery a causa del collegamento utile ad un'altra domanda che copre lo stesso terreno. L'altra domanda non viene visualizzata per una ricerca su "spazio dei nomi haskell". Niente di male con le altre risposte, ma posso solo accettare quella.

La soluzione menzionata qui utilizza Template Haskell, obiettivi, classi di tipi e altro per creare fondamentalmente un typeclass per ogni campo "HasName" con una singola funzione "nome". Ogni tipo di dati è quindi un'istanza di quella classe con la sua implementazione. Poi c'è un po 'di magia che non capisco completamente permettendo di coinvolgere diversi tipi.

Per i neofiti di Haskell che si chiedono di cosa si tratta, è perché i record sono fondamentalmente tuple con selettori di campo implementati come funzioni ordinarie che selezionano (ad es.) Il secondo elemento di quella tupla. Se si esportano queste funzioni di selezione dei campi, si siedono nello spazio dei nomi globale e prima o poi (di solito prima) si ottiene uno scontro.

Quindi - qualificate le importazioni (come nel mio esempio sopra) o provate a inventare nomi che non entrano in conflitto (prefissate il nome e sperate per il meglio).

Il materiale dell'obiettivo è di gran moda dal 2013 e consente la composizione di selettori di campo/getter + setter ecc. L'idea di base degli obiettivi non è troppo complicata ma l'implementazione mi passa per la testa.


Per la cronaca (ah!) Penso che la soluzione in un altro post è probabilmente quello che sto cercando, ma lo fa coinvolgere una grande quantità di magia (5 estensioni solo per finta namespacing record).

risposta

2

Una domanda simile è stato già chiesto, e si può vedere una risposta che suggerisce lenti qui: https://stackoverflow.com/a/17488365/516188

In questo momento le lenti sono una grande parola d'ordine nella comunità Haskell, che sicuramente hanno la loro utilità, e loro può essere parte della soluzione a questo problema di namespace, a lungo termine. Ma attualmente le persone che usano le lenti solo per risolvere quel problema sarebbero una piccola minoranza, penso. Come diceva Nikita Volkov, le importazioni e il prefisso qualificati sarebbero le soluzioni tipiche a questo punto.

AGGIORNAMENTO: scoperto circa this other option non ancora finalizzato ma sembra promettente. È menzionato qui alla fine di this blog post.

6

Generalmente ci sono solo due approcci, ma purtroppo non c'è consesus su di loro nella comunità:

  1. Posizionare i record con funzioni contro di loro in file separati e qualificato con alias completa utilizzare come in:

    import qualified Data.Person as Person; import Data.Person (Person) 
    
    isFred :: Person -> Bool 
    isFred p = (Person.name p) == "Fred" 
    

    Considerare questo approccio come in lingue come Java, dove un file contiene una sola classe.

  2. Posizionare i record nello stesso file, mentre precedono i nomi dei campi con i nomi dei record, ad es .:

    data Person = Person { 
        personName :: String, 
        personAge :: Int, 
        ... 
    } 
    

Nessuna delle lenti librerie si avvicina a questo problema.

+0

Tuttavia, nessuno di questi problemi risolve il problema. Sono solo diversi tipi di prefisso. Non è un problema in OO perché lo spazio dei nomi di metodi/attributi è limitato alla classe/oggetto - è comunemente solo lo spazio dei nomi di classe che è globale. Grazie comunque - l'ultima discussione che ho trovato su questo era di circa 18 mesi. –

+1

I colloqui sull'implementazione di un sistema di registrazione migliore sono stati come sempre. Ci sono dozzine di soluzioni suggerite. Esistono anche [dialetti Haskell, che risolvono il problema] (http://en.wikipedia.org/wiki/Frege_ (programming_language) #Records). Sfortunatamente, non ci resta che attendere che qualcuno di questi venga implementato. –

+0

Sì, ho passato in rassegna alcune delle discussioni più vecchie (sopra la mia testa). Ha la sensazione di uno di quei casi in cui aspetteremo la soluzione al 100% tra dieci anni, piuttosto che avere una soluzione al 90% anni fa. –

0

Ecco il mio approccio. In pratica, trovo che non ho spesso bisogno di esportare nomi di record, quindi l'inquinamento da spazio dei nomi è solo una preoccupazione all'interno del modulo stesso.Quindi io uso un breve prefisso, di solito la prima lettera del typeclass, in questo modo:

data Person = Person { 
    pName :: String, 
    ... 
} 

data Company = Company { 
    cName :: String, 
    ... 
} 

In situazioni in cui ho bisogno per consentire ad altri moduli per accedere direttamente a un campo, di solito è solo uno o due campi. E spesso voglio solo consentire l'accesso in lettura. Quindi in quel caso potrei essere un po 'creativo, forse qualcosa di simile.

module Whatever 
    { 
    Person, 
    personName, 
    Company, 
    companyName, 
    ... 
    } 

data Person = Person { 
    pName :: String, 
    ... 
} 

data Company = Company { 
    cName :: String, 
    ... 
} 

personName :: Person -> String 
personName = pName 

companyName :: Company -> String 
companyName = cName 
+0

Sì, puoi sempre aggiungere il prefisso al campo. Evidenzia il problema al costo di rendere il record di Haskell non corrispondente alle strutture esterne e di snellire il codice. –

Problemi correlati