2011-11-03 7 views
19

Sono un novizio in Haskell e spero che questa domanda non sia sciocca.La "lista" è gestita in modo specifico nel modello di corrispondenza di Haskell?

ho visto così tanto esempio che quando sto avendo una lista, io sono in grado di eguagliare e legare "elemento composizione" della lista per singola variabile:

listSizeDesc :: [a] -> String 
listSizeDesc [] = "Emtpy" 
listSizeDesc (x:xs) = "Something inside" 

Tuttavia, ho cercato di fare qualcosa Mi piace:

foo :: Int -> String 
foo 0 = "Zero" 
foo (n - 1) = "next number is " ++ show n 

Non funziona.

Mi sembra che sia (n-1) che (x: xs) descrivono come l'argomento è "creato" e associano il "componente" a un argomento. Il modo in cui l'elenco è abbinato appositamente progettato per facilitare la ricorsione? Coz mi sembra che questa logica di matching/argument-binding non si applica ad altre funzioni tranne (:).

+13

Sicuramente non una domanda stupida. Questa è la mia comprensione di un collega newbie: le liste non sono "speciali". L'abbinamento di modelli funziona con: perché: è un costruttore di tipi per elenchi. Funziona costruttori di tipi ma non per funzioni generali. In che modo questo lavoro è spiegato abbastanza bene [qui su WikiBooks] (http://en.wikibooks.org/wiki/Haskell/Pattern_matching) –

+1

Non esiste una domanda sciocca, a patto che sia ben fatta. – hugomg

+1

Risposta breve: No. –

risposta

14

La lista è "di tipo Sum" con un costruttore, qualcosa come:

data List a = 
    cons a (List a) 
    | nil 

È primo esempio è una corrispondenza modello su un tipo di dati (con zucchero sintattico per :).

Il secondo esempio è una corrispondenza di modello su numeri interi, che non sono una definizione di tipo datatypye. Nel numero intero, non esiste alcun modello che usi la sintassi.Si può scrivere il tuo esempio con:

foo :: Int -> String 
foo 0 = "Zero" 
foo n = "next number is " ++ show (n+1) 

Su un lato nota, se si codifica interi con tipi di dati come:

data Nat = Zero | Succ Nat deriving (Show) 

Quindi è possibile utilizzare il pattern match come si voleva inizialmente.

foo :: Nat -> String 
foo Zero = "Zero" 
foo [email protected](p) = "next number is " ++ show(n) 

Qui il modello Succ(p) interpreta il ruolo di n-1.

+0

Grandi esempi! Tutto ha senso per me ora: D Grazie mille –

+2

Quest'ultimo esempio è retrocesso. Per abbinare ciò che l'OP vuole, lo schema dovrebbe essere 'n' e la funzione dovrebbe mostrare' Succ n'. – jwodder

3
moo :: Int -> String 
moo 0 = "Zero" 
moo n = "next number is " ++ show (n + 1) 

n - 1 è un'applicazione di funzione ordinaria, non un modello. Un'eccezione veniva utilizzata per + e questo potrebbe essere il modello che stai seguendo. È possibile scrivere qualcosa come

goo :: Int -> String 
goo 0 = "Zero" 
goo (n+1) = "previous number is " ++ show n 

in hugs; è ancora possibile farlo con il ghc, se si include il pragma

{-#LANGUAGE NPlusKPatterns#-} 
+5

BTW, quei 'NPlusKPatterns' sono deprecati, in quanto confondono molti programmatori. Usare con cura! Inoltre, AFAIK abbinano solo numeri positivi. – fuz

+0

Sì, quello era il mio punto, immagino non espresso chiaramente. – applicative

18

Il problema incontrato è che il pattern matching funziona solo con i costruttori di dati. Un costruttore di dati è essenzialmente molto semplice; prende solo i valori dei dati e li raggruppa in una sorta di struttura. Ad esempio, data Foo = Bar a b prende semplicemente due pezzi di dati e li raggruppa sotto l'etichetta Foo. La funzione (:) che usi nel tuo primo esempio è più di una semplice funzione; è un costruttore di dati. Costruisce una nuova lista aggiungendo l'argomento di sinistra all'argomento di destra.

Ora, la corrispondenza del modello sta semplicemente facendo l'opposto di questo processo. Decostruisce un tipo di dati. Quando scrivi (x:xs) nel tuo pattern, stai estraendo le due parti di dati che il costruttore ha originariamente cucito insieme. Quindi, tutte le corrispondenze di pattern non fanno altro che estrarre i dati che un costruttore ha precedentemente cucito insieme.

C'è un'eccezione: n + k modelli. In Haskell98, ti è stato permesso di usare i pattern del modulo (n + k). Questa era una sorta di eccezione arbitraria ed è stata recentemente rimossa. Se lo desideri, puoi ancora usarlo se includi il pragma della lingua NPlusKPatterns.

tipo
+0

Ottima risposta. Sebbene abbia dato il "Accetta" ad un'altra risposta a causa dell'esempio intuitivo fornito, questa risposta è senza dubbio altrettanto valida. Vorrei poter accettare 2 risposte allo stesso tempo perché penso che entrambe le risposte siano un buon complimento l'una con l'altra. –

5

Ci sono già alcune grandi risposte, quindi non mi preoccuperò della domanda principale. Questo è non il miglior uso, ma quello che stavi cercando di fare può essere fatto con view patterns.

{-# LANGUAGE ViewPatterns #-} 

foo :: Int -> String 
foo 0 = "Zero" 
foo (pred -> n) = "Next number is " ++ show n 
4

solo mettere nel modo più semplice possibile:
Un elenco letteralmente è una serie di concatenazioni. Un numero potrebbe essere equivalente a il risultato di un'operazione aritmetica. La differenza è che il risultato di a : b è semplicemente a : b.


In dettaglio:

elenchi e (:) non sono un caso speciale. Facciamo in modo che la nostra:

data List2 a = End    -- equivalent of "[]" 
      | Cat a (List2 a) -- non-infix ":" 
    deriving (Show) 

Così [1, 2, 3], che == (1 : (2 : (3 : []))), sarebbe scritto come:

a = Cat 1 (Cat 2 (Cat 3 End)) 

Proprio come il modello-matching (x:xs), siamo in grado di modello-partita Lista2:

newTail End = End 
newTail (Cat _ x) = x 

Test:

*Main> tail [1,2,3] 
[2,3] 
*Main> newTail a 
Cat 2 (Cat 3 End) 
Problemi correlati