Ich beschäftige mich derzeit mit einer Funktion, die so aussieht:
foo = (\(a:b:c:d:e:f:_) -> foobar a b c d e f) . (++ repeat def)
Mit anderen Worten, bei einer gegebenen Liste werden die ersten sechs Elemente für etwas verwendet, und wenn die Liste weniger als sechs Elemente lang ist, wird sie def
als Ersatz für die fehlenden Elemente verwendet . Das ist total, aber die Teile davon sind nicht (genau wie map fromJust . filter isJust
), also mag ich es nicht. Ich habe versucht, dies so umzuschreiben, dass keine Parteilichkeit erforderlich ist, und habe Folgendes erhalten:
foo [] = foobar def def def def def def
foo [a] = foobar a def def def def def
foo [a,b] = foobar a b def def def def
foo [a,b,c] = foobar a b c def def def
foo [a,b,c,d] = foobar a b c d def def
foo [a,b,c,d,e] = foobar a b c d e def
foo (a:b:c:d:e:f:_) = foobar a b c d e f
Ich habe technisch getan, was ich will, aber jetzt ist das ein gigantisches Durcheinander. Wie kann ich dies eleganter und weniger repetitiv tun?
haskell
pattern-matching
Joseph Sible-Reinstate Monica
quelle
quelle
uncons :: Default a => [a] -> (a,[a])
die standardmäßig istdef
. Oder eine StandardeinstellungtakeWithDef
. Und / oder ein Ansichtsmuster / Mustersynonym. Dies erfordert jedoch das Schreiben eines zusätzlichen Hilfecodes.case xs ++ repeat def of a:b:c:d:e:f:_ -> ...
lokal genug ist, dass ich nicht zweimal darüber nachdenken würde, es einfach zu verwenden und alle zusätzlichen Maschinen zu überspringen, die die vorhandenen Antworten einführen. Es sind im Allgemeinen die globaleren Totalitätsargumente (die Invarianten beinhalten, die über mehrere Funktionsaufrufe hinweg beibehalten werden, z. B.), die mich nervös machen.takeWithDef
ist es nicht verwendbar, wenn es eine reguläre Liste zurückgibt, da wir das Muster übereinstimmen müssen: - / Die richtige Lösung ist das, was Daniel unten in seiner zweiten Antwort geschrieben hat.uncons
bekommt nur das erste Element, also ist es nicht so nützlich.Antworten:
Mit dem sicheren Paket können Sie beispielsweise schreiben:
quelle
Das ist zumindest kürzer:
Sie können leicht erkennen, dass die Muster vollständig sind, aber jetzt müssen Sie ein wenig nachdenken, um zu sehen, dass sie immer enden. Ich weiß also nicht, ob Sie es als Verbesserung betrachten können.
Ansonsten können wir es mit der Staatsmonade machen, obwohl es ein bisschen schwer ist:
Ich könnte mir auch vorstellen, einen unendlichen Stream-Typ wie zu verwenden
denn dann könnten Sie bauen
foo
von ausrepeat :: a -> S a
,prepend :: [a] -> S a -> S a
undtake6 :: S a -> (a,a,a,a,a,a)
konnten alle davon insgesamt sein. Wahrscheinlich nicht wert, wenn Sie einen solchen Typ noch nicht zur Hand haben.quelle
data S a = a :- S a; infixr 5 :-
sieht es ziemlich sauber aus;foo xs = case prepend xs (repeat def) of a:-b:-c:-d:-e:-f:-_ -> foobar a b c d e f
.Nur zum Spaß (und nicht empfohlen, dies ist zum Spaß), hier ist ein anderer Weg:
Der Typ, den Sie in der Musterübereinstimmung verwenden, entspricht der Übergabe einer natürlichen
takeDef
Textebene, um anzugeben, wie viele Elemente angezeigt werden sollen.quelle
foo (takeDef -> a:-b:-c:-d:-e:-f:-Nil) -> foobar a b c d e f
als eine Zeile. Ich zähle den Rest nicht, da es sich um Code handelt, der zur Wiederverwendung in einer Bibliothek vorhanden sein sollte. Wenn es nur für diesen Fall geschrieben werden muss, ist es eindeutig übertrieben, wie Sie sagen.