Actualmente estoy lidiando con una función que va así:
foo = (\(a:b:c:d:e:f:_) -> foobar a b c d e f) . (++ repeat def)
En otras palabras, dada una lista, usa los primeros seis elementos para algo, y si la lista tiene menos de seis elementos, la usa def
como un sustituto para los que faltan. Esto es total, pero las partes no son (solo como map fromJust . filter isJust
), por lo que no me gusta. Traté de reescribir esto para que no necesite usar ninguna parcialidad, y obtuve esto:
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
Técnicamente hice lo que quería, pero ahora esto es un desastre gigantesco. ¿Cómo puedo hacer esto de una manera más elegante y menos repetitiva?
case xs ++ repeat def of a:b:c:d:e:f:_ -> ...
es lo suficientemente local como para no pensarlo dos veces antes de usarlo y omitir toda la maquinaria adicional que las respuestas existentes están introduciendo. Generalmente son los argumentos de totalidad más globales (que involucran invariantes mantenidos a través de múltiples llamadas a funciones, por ejemplo) lo que me pone nervioso.
takeWithDef
no es utilizable si devuelve una lista regular, ya que necesitamos un patrón que coincida con eso: - / La solución adecuada es lo que Daniel escribió a continuación en su segunda respuesta. uncons
solo obtiene el primer elemento, por lo que no es tan útil.
uncons :: Default a => [a] -> (a,[a])
predeterminadodef
. O un incumplimientotakeWithDef
. Y / o un patrón de vista / sinónimo de patrón. Sin embargo, esto requiere escribir un código auxiliar auxiliar.