2017-03-06 5 views
3

Ich bin neu in Haskell und ich versuche, einfache Funktionen zu schreiben, um mich an die Syntax zu gewöhnen, ich möchte meine eigene Funktion zum Hinzufügen eines bestimmten Elements zu einer Liste an einem bestimmten Index schreiben. Hier ist, was ich in Atom (mein Texteditor) schrieb:Wie man Wächter in Haskell richtig benutzt?

addElem :: a->[a]->Int->[a] 
addElem elem list index 
| index <= 0   = elem:list 
| index < (length list) = a ++ (elem:b) where a = take index list; b = drop index list 
| otherwise    = list 

Die Idee ist, dass es nicht so lange wird ausflippen als Index ist ein Int und elem ist vom gleichen Typ wie die Elemente von list , aber wenn ich versuche, das in ghci zu laden, bekomme ich "parse error on` | '". Muss ich die Arten der Argumente einschränken? Ich lese, Lerne Du ein Haskell, aber ich bin nicht zu dem Teil gekommen, wo sie vollständig erklären, wie die Einrückungen funktionieren, also könnte mein Fehler auch da sein.

+3

Ein 'Where'-Block ist nicht an einen Ausdruck gebunden, d. H.' X, wobei decls' kein Ausdruck ist (im Gegensatz zu 'let decls in x', was ein Ausdruck ist). Ein 'where'-Block muss an eine Deklaration angehängt werden, in diesem Fall möchten Sie ihn vermutlich an die 'addElem'-Deklaration angehängt haben und müssen also * nach * dem Deklaration-Body platziert werden, zu dem auch die letzte Guard-Anweisung gehört. Beachten Sie, dass Parsing-Fehler niemals mit der Verwendung des falschen Typs zu tun haben - es bedeutet, dass der Compiler Ihren Code nicht einmal versteht, geschweige denn, ihn als falsch zu beurteilen. Dies ist auch kein Einrückungsfehler. – user2407038

+2

@ user2407038 das sollte eine Antwort sein – jberryman

+0

Willst du wirklich 'elem' ignorieren, wenn' index' zu groß ist? Das ist ein bisschen asymmetrisch im Vergleich zum Voranstellen des Elements, wenn 'index' <0 ist. Ich würde denken, dass 'sonst = Liste ++ [elem]' Sinn machen würde. – chepner

Antwort

11

where Blöcke müssen am Ende der gesamten Funktion auftreten und werden von allen Fällen gemeinsam verwendet. Sie haben wahrscheinlich eine let verwenden gemeint:

addElem :: a -> [a] -> Int -> [a] 
addElem elem list index 
| index <= 0   = elem:list 
| index < (length list) = let a = take index list; b = drop index list in a ++ (elem:b) 
| otherwise    = list 

Beachten Sie auch, dass let prägnanter als let (a,b) = splitAt index list in ... geschrieben werden konnte. splitAt ist auch im Prelude. Natürlich könnten Sie auch einfach den where Block an das Ende der Funktion verschieben (Haskell's Faulheit macht dies leicht zu verstehen).

addElem :: a -> [a] -> Int -> [a] 
addElem elem list index 
| index <= 0   = elem:list 
| index < (length list) = a ++ (elem:b) 
| otherwise    = list 
where 
    a = take index list 
    b = drop index list 

Ich persönlich mag diese weniger, weil sie suggeriert, dass a und b können an anderer Stelle in der Funktion verwendet werden.

Abschnitt 4.4.3 der 2010 Haskell Report geht genauer auf wo where zulässig ist.

Verwandte Themen