2011-03-29 7 views
6

Soy nuevo en Haskell, yo estaba tratando de escribir una función de cadena divididaHaskell comprensión flujo

delim = '|' 
splitStr::[Char]->[[Char]]->[[Char]] 
splitStr list y     
       | sL > 0 && sL < length(list) = splitStr (drop (sL+1) list) [subList]++y 
       | otherwise = [subList]++y 
       where 
        subList = takeWhile (\x -> x /= delim) list 
        sL = length(subList) 

split s = splitStr s [] 

Sin embargo, el código anterior siempre devuelve la cadena en orden inverso

Main> split "foo|bar|java|python" 
["python","java","bar","foo"] 

cambiar de y++[subList] a [subList]++y todavía da el mismo resultado. Sé que hay mejores formas de hacerlo, pero quiero saber por qué está sucediendo lo anterior.

Respuesta

5
splitStr (drop (sL+1) list) [subList]++y 

Esto se analiza como (splitStr (drop (sL+1) list) [subList])++y. Lo que quería es probablemente splitStr (drop (sL+1) list) ([subList]++y).

+0

¡Dios mío! brillante :) – Rnet

5

Aquí es decir, adicional a lo sepp2k dicho, algo acerca de cómo mejorar su código:

En su código que no es necesario un acumulador, ya que se puede explotar la pereza códigos. Reescribí tu código como lo haría:

split :: Char -> String -> [String] 
split delim "" = [] 
split delim s = chunk : split delim rest where 
(chunk,_:rest) = break (==delim) s 

¿Cómo funciona? Dividí la cuerda en el primer carácter, que es igual al delimitador. Devuelvo esa parte y llamo a la función recursivamente en el resto de la lista. Esto es muy eficiente, ya que Haskell no evaluará el resto de la lista hasta que sea necesaria.

+0

El problema estaba con la precedencia. Gracias por la alternativa :) – Rnet

+1

@Rnet: en Haskell, generalmente es una mala idea usar recursividad de cola con listas. Piense en una lista como una secuencia: el mejor algoritmo que la use debería poder calcular solo tanto como sea necesario y nada más. – fuz

+0

Tengo mucho que aprender, hasta ahora ha sido interesante :) – Rnet

Cuestiones relacionadas