Je traite actuellement une fonction qui va comme ceci:
foo = (\(a:b:c:d:e:f:_) -> foobar a b c d e f) . (++ repeat def)
En d'autres termes, étant donné une liste, il utilise les six premiers éléments pour quelque chose, et si la liste est inférieure à six éléments, il utilise def
comme remplaçant les éléments manquants. C'est total, mais les morceaux ne le sont pas (tout comme map fromJust . filter isJust
), donc je n'aime pas ça. J'ai essayé de réécrire ceci afin qu'il n'ait pas besoin d'utiliser de partialité, et j'ai obtenu ceci:
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
Techniquement, j'ai fait ce que je voulais, mais maintenant c'est un gigantesque bordel. Comment puis-je le faire de manière plus élégante et moins répétitive?
haskell
pattern-matching
Joseph Sible-Reinstate Monica
la source
la source
uncons :: Default a => [a] -> (a,[a])
défautdef
. Ou un défauttakeWithDef
. Et / ou un motif de vue / synonyme de motif. Cela nécessite cependant d'écrire du code auxiliaire.case xs ++ repeat def of a:b:c:d:e:f:_ -> ...
est suffisamment local pour que je ne pense pas à deux fois à simplement l'utiliser et à sauter toutes les machines supplémentaires que les réponses existantes introduisent. Ce sont généralement les arguments de totalité plus globaux (qui impliquent des invariants maintenus sur plusieurs appels de fonction, par exemple) qui me rendent nerveux.takeWithDef
n'est pas utilisable s'il renvoie une liste régulière, car nous devons faire correspondre ce modèle: - / La bonne solution est ce que Daniel a écrit ci-dessous dans sa deuxième réponse.uncons
obtient seulement le premier élément, donc ce n'est pas très utile.Réponses:
En utilisant le package sécurisé , vous pouvez écrire, par exemple:
la source
C'est au moins plus court:
Vous pouvez facilement voir que les modèles sont exhaustifs, mais maintenant vous devez réfléchir un peu pour voir qu'il se termine toujours. Je ne sais donc pas si vous pouvez considérer cela comme une amélioration.
Sinon, nous pouvons le faire avec la monade d'État, bien que ce soit un peu lourd:
Je pourrais aussi imaginer utiliser un type de flux infini comme
parce que vous pouvez construire
foo
surrepeat :: a -> S a
,prepend :: [a] -> S a -> S a
ettake6 :: S a -> (a,a,a,a,a,a)
, tous pourrait être totale. Probablement pas la peine si vous n'avez pas déjà un tel type à portée de main.la source
data S a = a :- S a; infixr 5 :-
il semble assez propre;foo xs = case prepend xs (repeat def) of a:-b:-c:-d:-e:-f:-_ -> foobar a b c d e f
.Juste pour le plaisir (et non recommandé, c'est pour les funsies), voici une autre façon:
Le type que vous utilisez dans la correspondance de motif revient à passer un naturel de type à
takeDef
dire combien d'éléments à regarder.la source
foo (takeDef -> a:-b:-c:-d:-e:-f:-Nil) -> foobar a b c d e f
comme une ligne. Je ne compte pas le reste car c'est du code qui devrait être dans une bibliothèque, pour être réutilisé. S'il doit être écrit uniquement pour ce cas, c'est clairement exagéré comme vous le dites.