2014-09-11 5 views
6

Sto risolvendo 99 Haskell Probemi. Ho risolto con successo il problema n. 21 e quando ho aperto solution page, è stata proposta la seguente soluzione:Un modello interessante

Inserire un elemento in una determinata posizione in un elenco.

insertAt :: a -> [a] -> Int -> [a] 
insertAt x xs (n+1) = let (ys,zs) = split xs n in ys++x:zs 

ho trovato modello (n + 1) interessante, perché sembra essere un modo elegante per convertire argomento 1 a base di insertAt in 0-based argomento split (la sua funzione da esercizi precedenti, essenzialmente lo stesso di splitAt). Il problema è che GHC non ha trovato questo modello che elegante, in realtà si dice: errore

Parse nel modello: n + 1

non credo che il ragazzo che ha scritto la risposta era stupido e mi piacerebbe sapere se questo tipo di schemi è legale in Haskell, e se lo è, come risolvere la soluzione.

+0

Anche se penso che i modelli 'n + k' abbiano un certo fascino, _convertendo_ tra una rappresentazione basata su 1 e zero, IMO non sarebbe mai stato un caso d'uso appropriato. Dovevano "decostruire" i numeri in modo ricorsivo. - FWIW, 'insertAt' dovrebbe essere a zero comunque, non dovrebbe? – leftaroundabout

+0

@leftaroundabout, 'insertAt' dovrebbe essere basato su 1 in base all'esempio fornito:' insertAt 'X' "abcd" 2' -> '" aXbcd "'. – Mark

+0

Sì, intendevo, dovrebbe essere _specified_ in modo che sia basato su 0, poiché tutte le funzioni dell'elenco standard di Haskell sono ([giustamente] (https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831 .html)). – leftaroundabout

risposta

12

Credo che sia stato removed from the language, e così è stato probabilmente in giro quando l'autore di 99 Haskell Problemi ha scritto quella soluzione, ma non è più in Haskell.

1

Nota che ora è possibile use view patterns instead of n+1.

Ad esempio:

{-# LANGUAGE ViewPatterns #-} 
module Temp where 
import Data.List (splitAt) 

split :: [a] -> Int -> ([a], [a]) 
split = flip splitAt 

insertAt :: a -> [a] -> Int -> [a] 
insertAt x xs (subtract 1 -> n) = let (ys,zs) = split xs n in ys++x:zs 
6

Il problema con n+k modelli risale a una decisione di progettazione in Haskell, di distinguere tra i costruttori e le variabili nei modelli dal primo carattere dei loro nomi. Se si torna a ML, una definizione di funzione comune potrebbe essere simile (utilizzando la sintassi Haskell)

map f nil = nil 
map f (x:xn) = f x : map f xn 

Come si può vedere, sintatticamente non c'è alcuna differenza tra f e nil sul lato sinistro della prima linea, ma hanno ruoli diversi; f è una variabile che deve essere associata al primo argomento a map mentre nil è un costruttore che deve essere confrontato con il secondo. Ora, ML fa questa distinzione osservando ogni variabile nell'ambito circostante e assumendo che i nomi siano variabili quando la ricerca fallisce. Pertanto, nil viene riconosciuto come costruttore quando la ricerca non riesce. Ma si consideri cosa succede quando c'è un errore di battitura nel modello:

map f niil = nil 

(due i s in niil). niil non è un nome costruttore in ambito, quindi viene trattato come una variabile e la definizione viene interpretata in modo non corretto in modo errato.

La soluzione di Haskell a questo problema è di richiedere che i nomi dei costruttori inizino con lettere maiuscole ei nomi delle variabili iniziano con lettere minuscole. E, per gli operatori/costruttori infissi, i nomi dei costruttori devono iniziare con : mentre i nomi degli operatori potrebbero non iniziare con :.Questo aiuta anche a distinguere tra attacchi decostruendo:

x:xn = ... 

è chiaramente un legame decostruire, perché non si può definire una funzione denominata :, mentre

n - m = ... 

è chiaramente una definizione di funzione, perché - puo' essere un nome costruttore

Tuttavia, i modelli n+k, come n+1, indicano che + è sia un nome di funzione valido, sia qualcosa che funziona come un costruttore nei modelli. Ora

n + 1 = ... 

è di nuovo ambiguo; potrebbe essere parte della definizione di una funzione denominata (+) oppure potrebbe essere una decostruzione della definizione della corrispondenza del modello di n. In Haskell 98, questa ambiguità è stato risolto dichiarando

n + 1 = ... 

definizione di una funzione, e

(n + 1) = ... 

un Deconstructing vincolante. Ma ovviamente non è mai stata una soluzione soddisfacente.