2015-11-24 9 views
6

Ich habe Haskell für ein paar Wochen gelernt, und ich habe eine Frage über die Verwendung des Unterstrichs (_) als Funktionsparameter. Ich denke, meine Frage wird mit einem konkreten Beispiel besser gestellt. Angenommen, ich möchte eine Funktion definieren, die das Element einer Liste basierend auf dem bereitgestellten Index extrahiert. Ja, ich weiß, dass (!!) bereits vordefiniert ist. Die beiden Möglichkeiten, dass ich die Funktion definieren kann (ich bin sicher, dass es mehr gibt) sind die folgenden:Haskell Unterstrich vs. explizite Variable

Version 1

indexedElement    :: [a] -> Int -> a 
indexedElement xs n | n < 0 = error "Index can not be negative." 
indexedElement [] n   = error "Index must be smaller than the length of the list." 
indexedElement (x:xs) 0  = x 
indexedElement (x:xs) n  = indexedElement xs (n - 1) 

Version 2

indexedElement   :: [a] -> Int -> a 
indexedElement _ n | n < 0 = error "Index can not be negative." 
indexedElement [] _  = error "Index must be smaller than the length of the list." 
indexedElement (x:_) 0  = x 
indexedElement (_:xs) n = indexedElement xs (n - 1) 

Die beiden Versionen sind offensichtlich sehr ähnlich. Der einzige Unterschied zwischen den beiden ist die Verwendung einer expliziten Variable oder eines Unterstrichs. Für mich bedeutet _, dass buchstäblich alles dort geschrieben werden kann, während eine explizite Variable wie n es offensichtlicher macht, dass das Argument eine ganze Zahl sein muss. Aus diesem Grund bevorzuge ich Version 1; aber der GHC-Quellcode für (!!) ist wie Version 2 geschrieben. Gibt es einen funktionalen Vorteil der zweiten Version? Wenn nicht, würden "hardcore" Haskell Programmierer Probleme mit Version 1 haben? Ich verstehe die Wichtigkeit einer konsistenten Art Code zu schreiben, also versuche ich die "ungeschriebenen Regeln" für die Programmierung in einer bestimmten Sprache zu befolgen. Dies ist ein Beispiel, bei dem ich die erste Version sehr bevorzuge, und ich glaube nicht, dass dies den Code schwieriger zu lesen macht. Ich weiß nicht, ob es aufgrund meines Mathe-Hintergrundes oder so ist, aber ich würde gerne hören, was Sie als erfahrene Haskell-Tierärzte denken.

+6

Ich bin über die Leistungsunterschiede nicht sicher (Sie könnten versuchen, Ausgabe des Kerns beider Versionen, um zu sehen, ob es Unterschiede gibt), aber die meisten haskeller bevorzugen die zweite Version, da sie die Anzahl der Namen reduziert, die gebunden werden müssen. Das '_ 'bedeutet, dass jeder Wert dorthin gehen kann (solange es der richtige Typ ist, der durch die Typensignatur gegeben ist. Es mag zwar natürlicher erscheinen,' n' zu verwenden, um eine ganze Zahl anzugeben, auch wenn sie nicht verwendet wird.) Denken Sie daran, dass nicht jeder diese Voreingenommenheit haben wird – bheklilr

+5

Sie können einen Kompromiss eingehen, indem Sie die Variable '_n' benennen, die die Warnungen bei Verwendung von' -Wall' ausschaltet, anzeigt, dass die Variable nicht verwendet wird und sie gleichzeitig benennt. – luqui

+0

@bheklilr Okay, ich schätze Ihre Eingabe.Ich werde mich selbst trainieren, um mit '_' besser zu werden. Danke, – basketballfan22

Antwort

17

Gibt es einen funktionalen Vorteil der zweiten Version?

Ich glaube nicht, dass sie einen operativen Unterschied haben. Aber ich finde die zweite Version besser lesbar. _ zeigt an, dass es überhaupt nicht verwendet wird. Während ich den Code lese, kann ich ihn einfach ignorieren und mich nur auf die anderen Parameter konzentrieren. Während in der ersten Version denke ich, dass n definiert ist, aber vielleicht der Autor vergessen hat, es zu verwenden? Oder vielleicht ist das Argument nicht erforderlich. Die zweite Version vermeidet diese Art von Überforderung. Aber das ist nur meine Meinung. :)

In der Tat, wenn Sie den Warn-Flag (-Wall) aktivieren und den Code kompilieren, wird es für die erste Version werfen Warnung:

[1 of 1] Compiling Main    (code.hs, code.o) 

code.hs:2:16: Warning: Defined but not used: ‘xs’ 

code.hs:3:19: Warning: Defined but not used: ‘n’ 

code.hs:4:19: Warning: Defined but not used: ‘xs’ 

code.hs:5:17: Warning: Defined but not used: ‘x’ 

code.hs:8:17: Warning: Defined but not used: ‘xs’ 
+0

Vielen Dank. Wie ich in meinem Beitrag erwähnt habe, habe ich nicht lange in Haskell programmiert; Folglich wusste ich nie von "-Wall". Wie schaltet man es an? Gib einfach einfach "-Wall" ganz am Anfang meines Quellcodes ein; und wenn ja, sollte es irgendwelchen Importen vorausgehen? – basketballfan22

+1

@ basketballfan22: Es ist eine Befehlszeilenoption für den Compiler. Wenn Sie mit dem 'ghc'-Befehl von Hand kompilieren, geben Sie ihn dort ein. Wenn Sie ein Build-Tool wie Cabal oder Stack verwenden, erfahren Sie in der Dokumentation, wie Sie die GHC-Optionen Ihres Projekts konfigurieren. –

+0

@LuisCasillas: Ah! Das ist großartig. Danke für die Hilfe. – basketballfan22