2015-01-02 17 views
5

Sto guardando un tutorial sui parser in haskell https://www.youtube.com/watch?v=9FGThag0Fqs. La lezione inizia con la definizione di alcuni parser veramente di base. Questi devono essere usati insieme per creare più parser più tardi. Uno dei parser di base è elemento. Questo è usato per estrarre un carattere dalla stringa che stiamo analizzando.Perché utilizzare lambda anziché la corrispondenza del modello?

Tutti i parser hanno il tipo seguente:

type Parser a = String -> [(a, String)]           

Il parser voce è definita in questo modo:

item :: Parser Char                
item = \inp -> case inp of              
        [] -> []             
        (x:xs) -> [(x,xs)] 

io non sono così abituato a questa sintassi, così sembra strano per me . Avrei scritto:

item' :: Parser Char                
item' [] = []                 
item' (x:xs) = [(x,xs)] 

test in ghci indica che sono uguali:

*Main> item "" 
[] 
*Main> item "abc" 
[('a',"bc")] 
*Main> item' "" 
[] 
*Main> item' "abc" 
[('a',"bc")] 

Il professore fa un commento breve di pensare sembra più chiaro, ma non sono d'accordo. Quindi le mie domande sono:

Sono davvero completamente identici? Perché la versione lambda è più chiara?

+2

Direi che è una questione di gusti. – augustss

risposta

11

ritengo questo deriva dalla pratica comune di scrittura

f :: Type1 -> ... -> Typen -> Result 
f x1 ... xn = someResult 

dove abbiamo esattamente n frecce funzione nel tipo, ed esattamente n argomenti nel lato sinistro dell'equazione. Ciò semplifica il collegamento di tipi e parametri formali.

Se Result è un tipo alias per una funzione, allora possiamo scrivere

f :: Type1 -> ... -> Typen -> Result 
f x1 ... xn y = something 

o

f :: Type1 -> ... -> Typen -> Result 
f x1 ... xn = \y -> something 

Quest'ultimo segue la convenzione precedente: n frecce, n variabili sinistra . Inoltre, sul lato destro abbiamo qualcosa di tipo Result, che rende più facile individuare. Il primo invece non lo fa, e si potrebbe perdere l'argomento extra quando si legge velocemente il codice.

Inoltre, questo stile lo rende facile convertire Result ad un Newtype invece di un tipo alias:

newtype Result = R (... -> ...) 

f :: Type1 -> ... -> Typen -> Result 
f x1 ... xn = R $ \y -> something 

Il codice postato item :: Parser Char è un esempio di questo stile quando n=0.

+2

Sono pienamente d'accordo sulla cosa newtype. Volete che il vostro parser sia almeno un Functor e Applicativo, e quindi avrete bisogno del nuovo tipo, quindi renderlo pronto per questo con un editing minimo è una buona cosa. – AndrewC

3

Penso che siano assolutamente uguali. La definizione in stile lambda inserisce un nome item in una funzione lambda anonima che esegue la corrispondenza del motivo all'interno. La definizione dello stile di corrispondenza del modello la definisce direttamente. Ma alla fine entrambe sono funzioni che eseguono il pattern matching. Penso che sia una questione di gusti personali.

Inoltre, la definizione lambda-stile potrebbe essere considerato di essere in pointfree stile, vale a dire una funzione definita, senza esplicitamente annotare i suoi argomenti in realtà non è molto pointfree in quanto l'argomento è ancora scritto (ma in un diverso posto), ma in questo caso non si ottiene nulla con questo.

Ecco un altro possibile definion, una via di mezzo a quei due:

item :: Parser Char 
item inp = case inp of 
       [] -> [] 
       (x:xs) -> [(x, xs)] 

E 'essenzialmente identico al lambda-stile, ma non pointfree.

+0

Non è affatto point-free. In '\ y -> ...', l'argomento chiamato 'y' è il" punto ". Solo perché non è sul lato sinistro di '=' non rende questa definizione senza punti. – amalloy

+0

@amalloy Probabilmente hai ragione (sto modificando la mia risposta in questo momento). Ma è più privo di punti della definizione diretta, non è vero? :) – zegkljan

4

Perché si dovrebbe evitare di definizioni di funzioni equational (di Roman Cheplyaka): http://ro-che.info/articles/2014-05-09-clauses

principali punti dal link qui sopra:

  • SECCO: i nomi delle funzioni e degli argomenti si ripetono -> più difficile da rifattorizziamo
  • spettacoli più chiare quali argomenti la funzione decide
  • facile aggiungere pragma (ad esempio per il profiling)
  • Sintatticamente più vicino al livello inferiore codice

Questo non spiega la lambda però ..

+0

@bheklilr ho aggiunto una lista – rethab

Problemi correlati