2013-04-12 13 views
7

Ciao, ho bisogno di ottenere l'ennesimo elemento di una lista ma senza usare il !! operatore. Sono estremamente nuovo per haskell quindi sarei grato se tu possa rispondere in modo più dettagliato e non solo una riga di codice. Questo è quello che sto provando in questo momento:Haskell - ottieni l'ennesimo elemento senza "!!"

nthel:: Int -> [Int] -> Int 
nthel n xs = 0 
let xsxs = take n xs 
nthel n xs = last xsxs 

ma ottengo: Errore di analisi (possibilmente indentazione errato)

Grazie in anticipo!

+1

'let xsxs = take n xs' - cosa si deve fare? – Adrian

risposta

12

C'è molto che è un po 'fuori qui,

nthel :: Int -> [Int] -> Int 

è tecnicamente corretto, in realtà vogliamo

nthel :: Int -> [a] -> a 

modo che possiamo utilizzare questo su liste di qualsiasi cosa (opzionale)

nthel n xs = 0 

Quello che hai appena detto è "Non importa quello che dai a nthel restituisci 0". che è chiaramente sbagliato.

let xsxs = ... 

Questo haskell non è legale. let ... in ... è un'espressione, non può essere utilizzata in toplevel.

Da lì non sono veramente sicuro di cosa dovrebbe fare.

Forse questo vi aiuterà a mettere sulla strada giusta

nthelem n [] = <???> -- error case, empty list 
nthelem 0 xs = head xs 
nthelem n xs = <???> -- recursive case 

riempimento Prova nella <???> con la tua ipotesi migliore e sono felice di aiutare da lì.

In alternativa è possibile utilizzare la sintassi di "corrispondenza del modello" di Haskell. Spiego come puoi farlo con gli elenchi here.

che cambia il nostro sopra per

nthelem n [] = <???> -- error case, empty list 
nthelem 0 (x:xs) = x --bind x to the first element, xs to the rest of the list 
nthelem n (x:xs) = <???> -- recursive case 

Fare questo è a portata di mano in quanto nega la necessità di utilizzare espliciti head e tail s.

+0

"Da lì non sono veramente sicuro di cosa dovrebbe fare." Sto provando a tagliare la lista fino all'ennesimo elemento e poi a prendere l'ultimo (cioè nesimo elemento). Ho capito che questo sarebbe il modo più semplice per prendere l'ennesimo elemento senza !! Se sai qualcosa di più semplice sentiti libero di condividerlo. Comunque, grazie per la risposta! – user43051

+0

L'ho fatto, questo è l'intero fondo del post è – jozefg

+0

Questo è quello che sto di stallo con - come mettere entrambi i Take e durano nel . Ci scusiamo per le domande stupide ma sto facendo haskell per un paio d'ore. – user43051

8

Penso che volevi dire questo:

nthel n xs = last xsxs 
    where xsxs = take n xs 

... che è possibile semplificare come:

nthel n xs = last (take n xs) 
+0

Esattamente! Grazie! Entrambi, votati, perché il mio voto è troppo basso per farlo da solo. :) – user43051

+3

@ user43051 Vorrei poter sopravvivere! :) Prego. –

+0

Funziona solo se la lista è lunga almeno quanto l'indice desiderato come take ritorna fino a n o lunghezza della lista così nthel 15 di "abc" restituisce 'c' invece di Nothing. –

1

Penso che si dovrebbe evitare di utilizzare last quando possibile - le liste sono fatte per essere utilizzati da il "front end", non dalla parte posteriore. Quello che vuoi è sbarazzarsi dei primi n elementi, e quindi ottenere la testa della lista rimanente (ovviamente si ottiene un errore se il resto è vuoto).È possibile esprimere questa abbastanza direttamente come:

nthel n xs = head (drop n xs) 

o più corto:

nthel n = head . drop n 

Oppure un po 'folle:

nthel = (head .) . drop 
0

Come sapete che questo elenco non sono indicizzate, naturalmente, ma può essere superare usando un consiglio comune.

Provare in ghci, zip [0..] "hello", Che cosa è circa zip [0,1,2] "hello" o zip [0..10] "hello"?
Partendo da questa osservazione, ora possiamo ottenere facilmente un modo per indicizzare la nostra lista.
Inoltre è una buona illustrazione dell'uso della pigrizia, un buon suggerimento per il tuo processo di apprendimento.

Quindi, in base a questo e utilizzando la corrispondenza dei modelli, possiamo fornire un algoritmo efficiente.

  1. Gestione dei casi limite (elenco vuoto, indice negativo).
  2. Sostituire l'elenco con una versione indicizzata tramite zip.
  3. Chiamare un progetto di funzione di supporto per elaborare in modo ricorsivo la nostra lista indicizzata.

Ora, per la funzione di supporto, l'elenco non può essere vuoto allora possiamo pattern match ingenuamente, e,

  • se il nostro indice è pari a n abbiamo un vincitore
  • altro, se il nostro elemento successivo è vuoto è oltre
  • , chiama la funzione di supporto con l'elemento successivo.

Nota aggiuntiva, dato che la nostra funzione può fallire (lista vuota ...) potrebbe essere una buona cosa avvolgere il nostro risultato usando il tipo Maybe.

Mettendo tutto questo insieme finiamo con.

nth :: Int -> [a] -> Maybe a 
nth n xs 
    | null xs || n < 0 = Nothing 
    | otherwise  = helper n zs 
     where 
     zs = zip [0..] xs 
     helper n ((i,c):zs) 
      | i == n = Just c 
      | null zs = Nothing 
      | otherwise = helper n zs