Pregunta

He incursionado con Haskell en el pasado, y recientemente se dieron de nuevo en serio, y yo estoy leyendo verdadera Haskell mundo. Algunos de los ejemplos que han brillaban, todavía tengo que entender. Tal en éste:

myLength []     = 0
myLength (x:xs) = 1 + myLength (xs)

No veo cómo funciona esto, ¿qué es en realidad 1 que se añade también? ¿Cómo es la recursividad volviendo algo que puede ser añadido a? Yo no lo entiendo.

Y aquí tenemos la siguiente:

splitLines [] = []
splitLines cs =
       let (pre, suf) = break isLineTerminator cs
       in  pre : case suf of 
                   ('\r':'\n':rest) -> splitLines rest
                   ('\r':rest)      -> splitLines rest
                   ('\n':rest)      -> splitLines rest
                   _                -> []

isLineTerminator c = c == '\r' || c == '\n'

¿Cómo funciona esto, lo que realmente está pre estando unida también? No veo cómo el resultado de la expresión caso es algo que previamente se puede concatenar a. Tal vez sólo necesito a alguien para explicar la evaluación de estas funciones en los detalles. Debo estar perdiendo algo muy importante.

Gracias de antemano!

EDIT: Lo sé, fue un copiar y pegar fallar. Lo sentimos.

EDIT 2: Parece que mi confusión era con lo que estas funciones eran en realidad / volver / tengo todo resuelto ahora. Gracias por las respuestas chicos, que finalmente se hace clic! Lo aprecio!

¿Fue útil?

Solución

En cuanto a la primera, que es una forma muy básica de la recursividad. Sin embargo, parece que falta una parte:

myLength [] = 0

Su acción consiste en la ampliación de un elemento en el momento de la lista y añadiendo uno al resultado. Para visualizar, considere la llamada

myLength [1,2,3]

que evaluará a:

1 + myLength [2,3]
1 + 1 + myLength [3]
1 + 1 + 1 + myLength []
1 + 1 + 1 + 0

que es 3.

En cuanto a la segunda, así, que ya han dividir la cadena en el siguiente salto de línea en dos partes: antes y suf. Ahora, suf comenzará ya sea con un \ n, o una \ r, o una \ r \ n. Queremos eliminar estos. Por eso, utilizamos la coincidencia de patrones. Vea cómo la variable resto es esencialmente la variable suf menos el personaje (s) línea rotura inicial.

Así que hemos pre, que es la primera línea, y el resto, que es el resto del texto. Así que con el fin de continuar resto de dividirse en líneas que llamamos splitlines en él de forma recursiva y concatenar el resultado de comprobar la validez.

Para visualizar, supongamos que tiene la cadena "foo \ nbar \ r \ nbaz".

Por lo tanto, cuando se llama, el resultado será:

[ pre => foo, suf => \nbar\r\nbaz, rest => bar\r\n\baz ]
foo : splitLines bar\r\nbaz

entonces splitlines se llama de nuevo, y el resultado se expandió a:

[ pre => bar, suf => \r\nbaz, rest = baz ]
foo : bar : splitLines baz

a continuación, una vez más:

[ pre => baz, suf => [], rest = [] ]
foo : bar : baz

que es el resultado final.

Otros consejos

Creo que la definición de myLength pierde el caso en que la lista está vacía:

myLength [] = 0
myLength (x:xs) = 1 + myLength (xs)

Con esta definición, el myLength de una lista vacía es 0. El Patten (x:xs) descomprime una lista en el primer elemento, a, y una lista con el resto de los artículos, xs. Si la lista tiene un artículo, xs es una lista vacía, por lo que el resultado es 1 + 0. Y así sucesivamente.

La recursividad es más fácil de entender cuando nos fijamos en el caso base, y luego ver cómo cada nivel de recursividad se basa en el resultado. (El caso base es el caso en el que la función no llama a sí mismo. Si una función recursiva no tiene un caso base, la salida será infinito.)

En el segundo ejemplo, el caso base (el último caso en el caso-DECLARACIÓN) es también una lista vacía. Así pre siempre será añadido a la lista, lo que dará lugar a una nueva, más largo, lista.

Re: myLength (x:xs) = 1 + myLength (xs) - esto es "medio" de la definición de myLength, se dice, por coincidencia de patrones, que si el argumento tiene una cabeza y una cola, entonces el resultado es una mayor que la llamada recursiva de cola en la cola - es necesario que haya otro medio para decir que el resultado es 0 cuando el argumento no puede coincidir con x:xs, es decir, cuando el argumento es una lista vacía

.

En el segundo caso, la posibilidad de diferentes patrones de juego está hecho sólo un poco más epxlicit través case.

Por cierto, la pereza no es una cuestión clave aquí - ML, con ganas de evaluación, pero la coincidencia de patrones muy parecido a Haskell, que funciona de manera muy similar. Parece que la coincidencia de patrones es lo que realmente necesita para repasar acerca.

En primer lugar el primer ejemplo debería ser así ( editar parece que te fijas ahora):

myLength []     = 0
myLength (x:xs) = 1 + myLength (xs)

funciona así: dicen que le dan una lista con tres elementos, vuelve uno más la longitud de la cola (que es uno más la longitud de la cola (que es uno más la longitud de la cola, (que se [] en este punto), que es 1), que es w), que es 3 (la respuesta final). Tal vez paréntesis anidados le ayudará a entender la misma. ; -)

Es instructivo examinar cuáles serían las firmas de características de sus funciones. Podrían ser:

myLength :: [a] -> Int

En myLength, se añade 1 al resultado de la llamada recursiva a myLength, que es un Int, que a su vez resulta en un Int.

splitLines :: [Char] -> [[Char]]

En splitLines, pre (un [Char]) se antepone al resultado de la declaración del caso, que, al mirar los casos, o bien es el resultado de una llamada recursiva a splitLines, que es [[Char]]; o una lista vacía. En ambos casos, anteponiendo pre (a [Char]) resultará en un [[Char]] a su vez.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top