2011-04-01 17 views
6

Como ejercicio, escribí una breve función Haskell que devuelve los primeros cuatro caracteres de una cadena, concatenada. Tuve grandes problemas para convertir los caracteres en cadenas y recurrí a un feo replicate hack. ¿Cuál es la mejor manera de mejorar esta función? (Supongo que tanto el patrón y la salida se pueden mejorar.)¿Cómo debería refactorizar este código Haskell para hacerlo más elegante?

concatFirstFour :: [Char] -> [Char] 
concatFirstFour (a:b:c:d:_) = (replicate 1 a) ++ (replicate 1 b) ++ (replicate 1 c) ++ (replicate 1 d) 
concatFirstFour xs = error "Need at least four characters." 

Actualización: Muchas gracias, todo el mundo. Aprendí varias cosas de todas las respuestas y comentarios. Entiendo los tipos mucho mejor.

Aquí está el código que terminé usando:

initFirstFour :: [a] -> [a] 
initFirstFour str 
       | length str > 3 = take 4 str 
       | otherwise  = error "Need at least four characters." 

Actualización 2: Cambiado el segundo patrón de XS a _ por el comentario de ptival. Lazy eval FTW.

Actualización 3: Limpiadores de guardias del comentario de tew88.

+4

'concatFirstFour :: [a] -> [a]' es mejor – alternative

+1

Tenga en cuenta que no necesita nombrar 'xs' en la última línea de su código, ya que el argumento nunca se usa en el cuerpo de la función. Puedes reemplazarlo con wilcard '_' – Ptival

Respuesta

10
concatFirstFour (a:b:c:d:_) = [a,b,c,d] 
concatFirstFour _   = error "Need at least four characters." 

o

concatFirstFour = take 4 

pero este último no falla en las listas cortas ...


También tenga en cuenta que no es necesario especificar el tipo es un [ Char] (o String), ya que nunca usas esta suposición en el código. Deje que sea [a] -> [a].

4

Las cadenas son solo listas de caracteres, por lo que no es necesario convertir caracteres en cadenas y luego concatenar las cadenas. Hay algunas maneras diferentes de hacer esto.

En primer lugar, si desea una lista con sólo un elemento, puede utilizar [x]. Entonces:

concatFirstFour (a:b:c:d:_) = [a] ++ [b] ++ [c] ++ [d] 

Pero esto no es realmente necesario. Se podía hacer esto:

concatFirstFour (a:b:c:d:_) = [a, b, c, d] 

O esto:

concatFirstFour (a:b:c:d:_) = a:b:c:d:[] 

O, mi forma preferida:

concatFirstFour str = take 4 str 

Desde str es sólo una lista, puede take los cuatro primeros caracteres para obtener una nueva "cuerda".

2

Similar a la solución de Ptival que usa patrones de coincidencia. Pero este no falla con cadenas de menos de 4 caracteres.

concatFirstFour (a:b:c:d:_) = [a,b,c,d] 
concatFirstFour xs  = xs 
4

Se podría considerar el uso de la palabra clave 'en otro caso' como parte de su expresión guardia:

initFirstFour :: [a] -> [a] 
initFirstFour xs 
    | length xs > 3 = take 4 xs 
    | otherwise  = error "Need at least four characters." 

Creo que esto es un poco más fácil de leer (y elegante) que su método elegido de coincidencia de patrones.

Cuestiones relacionadas