2016-07-24 26 views
2

Ich lerne Haskell. Dies ist ein triviales Beispiel, aber ich würde gerne das Konzept verstehen, warum ich den Mustervergleich in der Lambda-Funktion im folgenden Beispiel nicht verwenden kann (dh warum führt die Filterfold-Funktion, aber Filterfold, einen Laufzeitfehler aus):Muster passend in Lambda

-- Runs 
filterfold' :: (a -> Bool) -> [a] -> [a] 
filterfold' p zs = foldr (\y zs -> if (p y) then y:zs else zs) [] zs 

-- Runtime error: Non-exhaustive patterns in lambda 
filterfold :: (a -> Bool) -> [a] -> [a] 
filterfold p (z:zs) = foldr (\y (z:zs) -> if (p y) then y:(z:zs) else (z:zs)) [] (z:zs) 

Antwort

4

Sie können es verwenden, aber wie der Compiler Sie sagt Ihnen, einen Fall fehlen (wenn der Eingang [])

sehen Sie, wenn Sie z:zs sagen, es wird versuchen, dieses Muster zu passen mit der Eingabe-Liste - wenn Sie

  • Eingabe [1,2,3] = 1:[2,3] Sie erhalten z=1 und zs=[2,3]
  • aber wenn der Eingang [] Sie kein z und zs so dass z:zs = [] (technisch sie basieren auf unterschiedlichen Herstellern der Liste-Datentyp)

Also zur Laufzeit wird es nicht kennen lernen wie man mit diesem Fall/Muster umgehen kann, wenn es [] sieht und die Ausnahme auslöst.

wenn man genau an Ihrem Beispiel aussehen sollten Sie sehen, dass Sie sowieso nie die Teile tatsächlich nutzen (was bedeutet, z oder zs - man kann sich nur als z:zs wieder verwenden), so kann ich Ihnen nicht sagen, wie es besser machen

trotzdem können Sie die case verwenden - Ausdruck innerhalb eines Lambda:

... = foldr (\ x zs = case zs of 
         z:zs -> ... 

oder können Sie die LambdaCase Erweiterung verwenden, um es kürzer etwas zu machen.

+0

Also, das ZS aus dem Argument der Filterfold-Funktion ist im Geltungsbereich, aber anstatt das 'z' aus dem Filterfold zu verwenden, versucht es, einen Mustervergleich lokal innerhalb des Lambda durchzuführen? – Daniel

+1

ja die 'z' und' zs' innerhalb des Lambdas werden verschiedene sein ('foldr' wird * ihnen * zur Verfügung stellen) - deshalb sollten Sie Parameter/Argumentnamen für Lambda-Argumente nicht wiederverwenden - Sie * führen * diese Namen mit ein dein Lambda und du wirst das Einmalige aus dem Outer-Scope verstecken - also wenn du das 'z' und' zs' aus dem Outer-scope in 'filterfold' verwenden willst, solltest du es einfach in' foldr (\ y) umbenennen ys -> ...) '(oder welcher Name auch immer anders ist als' p', 'z',' zs' und 'y';)) – Carsten

+0

aber bitte beachten Sie: wenn Sie das zweite Argument von Funktion (das Lambda), die du zu "foldr" gibst, dann brauchst du wahrscheinlich nicht den 'foldr' an erster Stelle, da du nur auf den" Kopf "der Liste eingibst, wenn er nicht leer ist oder auf den zweiten Standard geht Argument von 'foldr' – Carsten