Comenzando con Haskell


755

Durante unos días he tratado de entender el paradigma de programación funcional en Haskell. Lo hice leyendo tutoriales y viendo screencasts, pero nada parece realmente quedarse. Ahora, al aprender varios lenguajes imperativos / OO (como C, Java, PHP), los ejercicios han sido una buena manera de hacerlo. Pero como realmente no sé de lo que es capaz Haskell y porque hay muchos conceptos nuevos para utilizar, no sé por dónde empezar.

Entonces, ¿cómo aprendiste Haskell? ¿Qué te hizo realmente "romper el hielo"? Además, ¿alguna buena idea para comenzar los ejercicios?


Respuestas:


2476

Voy a ordenar esta guía por el nivel de habilidad que tenga en Haskell, desde un principiante absoluto hasta un experto. Tenga en cuenta que este proceso llevará muchos meses (¿años?), Por lo que es bastante largo.

Principiante absoluto

En primer lugar, Haskell es capaz de cualquier cosa, con suficiente habilidad. Es muy rápido (solo en C y C ++ en mi experiencia), y puede usarse para cualquier cosa, desde simulaciones hasta servidores, guis y aplicaciones web.

Sin embargo, hay algunos problemas que son más fáciles de escribir para un principiante en Haskell que otros. Los problemas matemáticos y los programas de proceso de listas son buenos candidatos para esto, ya que solo requieren el conocimiento más básico de Haskell para poder escribir.

En primer lugar, algunas buenas guías para aprender los conceptos básicos de Haskell son el tutorial de aprendizaje feliz de haskell y los primeros 6 capítulos de aprender un haskell . Mientras lee esto, es una muy buena idea también resolver problemas simples con lo que sabe.

Otros dos buenos recursos son la programación de Haskell desde los primeros principios y la programación en Haskell . Ambos vienen con ejercicios para cada capítulo, por lo que tiene pequeños problemas simples que coinciden con lo que aprendió en las últimas páginas.

Una buena lista de problemas para probar es la página de problemas de haskell 99 . Estos comienzan muy básicos y se vuelven más difíciles a medida que avanza. Es una buena práctica hacer muchas de ellas, ya que te permiten practicar tus habilidades en funciones de recursión y de orden superior. Recomendaría omitir cualquier problema que requiera aleatoriedad, ya que es un poco más difícil en Haskell. Verifique esta pregunta de SO en caso de que quiera probar sus soluciones con QuickCheck (consulte Intermedio a continuación).

Una vez que haya hecho algunos de esos, podría pasar a resolver algunos de los problemas del Proyecto Euler . Estos se ordenan por la cantidad de personas que los han completado, lo que es un buen indicio de dificultad. Estos prueban su lógica y Haskell más que los problemas anteriores, pero aún así debería poder hacer los primeros. Una gran ventaja que tiene Haskell con estos problemas es que los números enteros no tienen un tamaño limitado. Para completar algunos de estos problemas, será útil haber leído los capítulos 7 y 8 para aprender también sobre Haskell.

Principiante

Después de eso, debe tener un buen manejo de las funciones de recursión y de orden superior, por lo que sería un buen momento para comenzar a resolver algunos problemas del mundo real. Un buen lugar para comenzar es Real World Haskell (libro en línea, también puede comprar una copia impresa). Encontré los primeros capítulos introducidos demasiado rápido para alguien que nunca antes había hecho programación funcional / usado recursividad. Sin embargo, con la práctica que habría tenido al hacer los problemas anteriores, debería encontrarlo perfectamente comprensible.

Trabajar en los problemas del libro es una excelente manera de aprender a manejar abstracciones y construir componentes reutilizables en Haskell. Esto es vital para las personas acostumbradas a la programación orientada a objetos (oo), ya que los métodos normales de abstracción oo (clases oo) no aparecen en Haskell (Haskell tiene clases de tipo, pero son muy diferentes a las clases oo, más bien como interfaces oo ) No creo que sea una buena idea omitir capítulos, ya que cada uno presenta muchas ideas nuevas que se utilizan en capítulos posteriores.

Después de un tiempo llegarás al capítulo 14, el temido capítulo de las mónadas (dum dum dummmm). Casi todos los que aprenden Haskell tienen problemas para comprender las mónadas, debido a lo abstracto que es el concepto. No puedo pensar en ningún concepto en otro lenguaje que sea tan abstracto como las mónadas en la programación funcional. Monads permite que muchas ideas (como operaciones de E / S, cálculos que pueden fallar, análisis, ...) se unifiquen bajo una sola idea. Así que no se desanime si después de leer el capítulo de las mónadas realmente no los comprende. Me pareció útil leer muchas explicaciones diferentes de mónadas; cada uno da una nueva perspectiva sobre el problema. Aquí hay una muy buena lista de tutoriales de mónada . Recomiendo el All About Monads , pero los otros también son buenos.

Además, los conceptos tardan un tiempo en asimilarse realmente. Esto viene a través del uso, pero también a través del tiempo. ¡Encuentro que a veces dormir con un problema ayuda más que cualquier otra cosa! Eventualmente, la idea hará clic y te preguntarás por qué te costó entender un concepto que en realidad es increíblemente simple. Es increíble cuando esto sucede, y cuando sucede, puede encontrar a Haskell como su lenguaje de programación imperativo favorito :)

Para asegurarte de que estás entendiendo perfectamente el sistema de tipo Haskell, debes tratar de resolver 20 ejercicios intermedios de haskell . Esos ejercicios usan nombres divertidos de funciones como "furry" y "banana" y le ayudan a comprender bien algunos conceptos básicos de programación funcional si aún no los tiene. Buena manera de pasar la noche con un montón de papeles cubiertos con flechas, unicornios, salchichas y plátanos peludos.

Intermedio

Una vez que comprenda Mónadas, creo que ha hecho la transición de un programador principiante de Haskell a un intermediario de haskeller. Entonces, ¿a dónde ir desde aquí? Lo primero que recomendaría (si aún no los ha aprendido aprendiendo mónadas) son los diversos tipos de mónadas, como Reader, Writer y State. Una vez más, el mundo real Haskell y All about Mónadas ofrece una gran cobertura de esto. Para completar su entrenamiento de mónada, es imprescindible aprender sobre los transformadores de mónada. Estos le permiten combinar diferentes tipos de mónadas (como un lector y una mónada estatal) en una sola. Para empezar, esto puede parecer inútil, pero después de usarlos por un tiempo, se preguntará cómo vivió sin ellos.

Ahora puedes terminar el libro de Haskell del mundo real si quieres. Omitir capítulos ahora realmente no importa, siempre y cuando tenga mónadas. Simplemente elija lo que le interesa.

Con el conocimiento que tendría ahora, debería poder usar la mayoría de los paquetes en cabal (bueno, al menos los documentados ...), así como la mayoría de las bibliotecas que vienen con Haskell. Una lista de bibliotecas interesantes para probar sería:

  • Parsec : para analizar programas y texto. Mucho mejor que usar expresiones regulares. Excelente documentación, también tiene un capítulo de Haskell del mundo real.

  • QuickCheck : un programa de prueba muy bueno. Lo que haces es escribir un predicado que siempre debe ser verdadero (por ejemplo length (reverse lst) == length lst). Luego pasa el predicado QuickCheck, y generará muchos valores aleatorios (en este caso, listas) y prueba que el predicado es verdadero para todos los resultados. Ver también el manual en línea .

  • HUnit : Unidad de pruebas en Haskell.

  • gtk2hs : el marco gui más popular para Haskell, le permite escribir aplicaciones gtk en Haskell.

  • happstack : un marco de desarrollo web para Haskell. No utiliza bases de datos, en su lugar, un almacén de tipos de datos. Documentos bastante buenos (otros marcos populares serían snap y yesod ).

Además, hay muchos conceptos (como el concepto Monad) que eventualmente debería aprender. Esto será más fácil que aprender Mónadas la primera vez, ya que tu cerebro estará acostumbrado a lidiar con el nivel de abstracción involucrado. Una muy buena visión general para aprender sobre estos conceptos de alto nivel y cómo encajan entre sí es Typeclassopedia .

  • Aplicativo: una interfaz como Monads, pero menos potente. Cada mónada es aplicativa, pero no al revés. Esto es útil ya que hay algunos tipos que son Aplicativos pero que no son Mónadas. Además, el código escrito usando las funciones Aplicativas es a menudo más componible que escribir el código equivalente usando las funciones Monad. Vea Functores, Funcionadores aplicativos y Monoides de la guía Aprenda un haskell.

  • Plegable , de Traversable : clases de tipos que muchos abstracta de las operaciones de listas, de modo que las mismas funciones se pueden aplicar a otros tipos de contenedores. Vea también la explicación de la wiki de Haskell .

  • Monoide : un monoide es un tipo que tiene un valor cero (o mempty), y una operación, anotada <>que une dos monoides, tal que x <> mempty = mempty <> x = xy x <> (y <> z) = (x <> y) <> z. Estas se llaman leyes de identidad y asociatividad. Muchos tipos son monoides, como los números, con mempty = 0y <> = +. Esto es útil en muchas situaciones.

  • Flechas : las flechas son una forma de representar cálculos que toman una entrada y devuelven una salida. Una función es el tipo más básico de flecha, pero hay muchos otros tipos. La biblioteca también tiene muchas funciones muy útiles para manipular flechas: son muy útiles incluso si solo se usan con funciones antiguas de Haskell.

  • Matrices : las diversas matrices mutables / inmutables en Haskell.

  • ST Monad : le permite escribir código con un estado mutable que se ejecuta muy rápidamente, sin dejar de ser puro fuera de la mónada. Vea el vínculo para mas detalles.

  • FRP: Programación funcional reactiva, una nueva forma experimental de escribir código que maneja eventos, disparadores, entradas y salidas (como una interfaz gráfica de usuario). Sin embargo, no sé mucho sobre esto. La charla de Paul Hudak sobre yampa es un buen comienzo.

Hay muchas características nuevas del lenguaje que deberías echar un vistazo. Solo los enumeraré, puedes encontrar mucha información sobre ellos en google, el haskell wikibook , el sitio haskellwiki.org y la documentación de ghc .

  • Clases de tipo multiparamétrico / dependencias funcionales
  • Escriba familias
  • Tipos cuantificados existencialmente
  • Tipos fantasma
  • GADTS
  • otros...

Gran parte de Haskell se basa en la teoría de categorías , por lo que es posible que desee analizar eso. Un buen punto de partida es la teoría de categorías para informáticos . Si no desea comprar el libro, el artículo relacionado con el autor también es excelente.

Finalmente, querrá aprender más sobre las diversas herramientas de Haskell. Éstas incluyen:

  • ghc (y todas sus características)
  • cabal : el sistema de paquetes Haskell
  • darcs : un sistema de control de versiones distribuido escrito en Haskell, muy popular para los programas Haskell.
  • eglefino : un generador de documentación automática Haskell

Mientras aprende todas estas nuevas bibliotecas y conceptos, es muy útil escribir un proyecto de tamaño moderado en Haskell. Puede ser cualquier cosa (por ejemplo, un pequeño juego, analizador de datos, sitio web, compilador ). Trabajar en esto le permitirá aplicar muchas de las cosas que ahora está aprendiendo. Te quedas en este nivel durante siglos (aquí es donde estoy).

Experto

Le llevará años llegar a esta etapa (¡hola desde 2009!), Pero desde aquí supongo que comenzará a escribir documentos de doctorado, nuevas extensiones de ghc y generar nuevas abstracciones.

Obteniendo ayuda

Finalmente, en cualquier etapa de aprendizaje, existen múltiples lugares para obtener información. Estos son:

  • el canal #haskell irc
  • Las listas de correo . Vale la pena inscribirse solo para leer las discusiones que tienen lugar, algunas son muy interesantes.
  • otros lugares listados en la página de inicio de haskell.org

Conclusión

Bueno, esto resultó más de lo que esperaba ... De todos modos, creo que es una muy buena idea dominar Haskell. Lleva mucho tiempo, pero eso se debe principalmente a que estás aprendiendo una forma de pensar completamente nueva al hacerlo. No es como aprender Ruby después de aprender Java, sino como aprender Java después de aprender C. Además, estoy descubriendo que mis habilidades de programación orientada a objetos han mejorado como resultado de aprender Haskell, ya que estoy viendo muchas formas nuevas de abstraer ideas.


35
Yay flechas! Primero dejas que las mónadas den forma a tu cerebro, luego te paras sobre tu cabeza y piensas en las comonads, y luego haces ambas cosas al mismo tiempo para obtener flechas :) Hay un gran poder expresivo en Haskell que se puede abrir con el nivel de letra programación también.
ephemient el

13
@nanothief Monades más poderoso, pero también menos compositivo ... muchas personas usan mónadas donde podrían haberse salido con un Applicativecódigo más limpio . La mayoría de las cosas que son Functors también son Monads, pero no andas usando >>=y returncuándo fmapserá suficiente, porque este último conduce a un código mucho más simple si puedes usarlo.
Tom Crockett

8
@pelotom, agregué el enlace typeclassopedia, así como mejores razones para usar Applicative en esa sección, y eliminé la sección Functor. Es difícil poner los conceptos Mónada y Aplicativo en el orden correcto debido al énfasis en Mónadas en la mayoría del material de enseñanza (incluido RWH). Por otro lado, la enseñanza de un tutorial de haskell ha recorrido un largo camino desde que escribí inicialmente la respuesta (casi 2 años: O), y enseña Aplicativo antes de Monad, quizás esa debería ser la forma recomendada de aprender haskell.
David Miani

2
Buen consejo. Empecé esto hace más de un año, y estoy en la etapa intermedia. Comentarios: el capítulo de la mónada de RWH (capítulo 14) está mal explicado. Leer la versión en línea de RWH es beneficioso, ya que contiene comentarios de crowdsourcing que ayudan al capítulo. FWIW, podría haber inventado mónadas , fue el tutorial de mónada que mejor funcionó para mí.
Tom

66
@tomf: ¡Gracias! Siempre me ha sorprendido lo bien que ha funcionado esta respuesta: han pasado casi cinco años desde que la escribí, pero sigue siendo fuerte. Sin embargo, tendré que actualizarlo pronto, ya que está un poco desactualizado. No menciona lentes, tuberías, tipos de restricciones, la plataforma haskell, números de nivel de tipo, y son temas nuevos muy importantes desde que esto se escribió. Tiene razón en que RWH ya no es tan bueno, no se ha actualizado en mucho tiempo y muchos de los ejemplos no se están compilando. Me alegro de que todavía te haya sido útil.
David Miani

180

¡Un colega mío tuvo una buena experiencia con Learn You a Haskell for Great Good! .

Tutorial dirigido a personas que tienen experiencia en lenguajes de programación imperativos pero que no han programado en un lenguaje funcional antes.

Y mira las respuestas aquí también


27
Secundo esto. Además, como no es obvio, aquí hay un enlace a una versión descargable en PDF del tutorial: learnyouahaskell.com/learnyouahaskell.pdf El diseño web es excelente, pero también me gusta tener una copia para el metro.
Telemachus

8
Empecé con esto, pero mi opinión es que deberías ir directamente a Real World Haskell. La diferencia es como aprender C de K&R o "C for dummies", que trata de ser simple, pero se pierde cosas importantes con su enfoque. Creo que es mejor aclarar los hechos en lugar de tratar de aprender Haskell "de la manera imperativa".
John Smith

77
Me encanta esto, y he invertido mucho tiempo en esto y en el mundo real Haskell. En mi opinión, "Learn You a Haskell" ofrece una visión más profunda que Real World Haskell, aunque ambos son excelentes recursos.
Charlie Flowers

77
@ abababa22 Creo que leer LYAH primero y luego ir a RWH es la mejor idea. LYAH no te enseña solo a Haskell; Te enseña programación funcional. Empiezas a pensar de manera funcional cuando resuelves problemas. Claramente, solo LYAH no sería suficiente para escribir una aplicación grande, pero se inclina de la manera correcta. Si eres de origen imperativo, esta es la mejor manera, OMI
Abdulsattar Mohammed

44
@Telemachus Solo para tener en cuenta: el PDF no es la versión final, al menos le falta el último capítulo.
sdcvvc

103

Aquí hay un buen libro que puedes leer en línea: Real World Haskell

La mayoría de los programas de Haskell que he realizado han sido para resolver problemas del Proyecto Euler .

Un consejo que leí no hace mucho fue que deberías tener un conjunto estándar de problemas simples que sabes cómo resolver (en teoría) y luego, cuando intentas aprender un nuevo idioma, implementas esos problemas en ese idioma.


2
Real World Haskell en mi experiencia es genial, hasta que llegues al capítulo 5. A partir de entonces no lo recomendaría.
MasterMastic

¿Por qué @MasterMastic? ¿Cuál es el problema más allá del capítulo 5? Me gustaría saber antes de gastar el dinero.
Jay Blanchard

@JayBlanchard En el capítulo 5 comienzas a obtener un ejemplo concreto de una biblioteca, lo cual es bueno, pero te dicen lo que van a hacer, lo hacen, pero no explican por qué por completo, y no del todo claro, y hay bastantes literales mágicos hexadecimales. Solo estás haciendo los movimientos. Ese no fue el mayor problema para mí, aunque el mayor problema fue que el libro depende en gran medida de ese tipo de ejemplos difíciles y largos (lo suficiente como para tomar más de un capítulo completo). Apenas puedes leer las partes que quieres. Creo que grandes autores, conocimiento increíble pero ejecución extremadamente pobre.
MasterMastic


69

Para agregar las respuestas de otros, hay una útil que lo ayudará a codificar (por ejemplo, al resolver problemas del proyecto Euler): Hoogle . Puede usar la interfaz de línea de comandos o la interfaz web .

Línea de comando

Después de instalar la plataforma Haskell, asegúrese de cabal install hoogle

Ejemplo de uso de Hoogle:

Tiene una función f x = 3 * x + 1y desea aplicarla (5 :: Int), luego aplicarla en el resultado y en ese resultado, y así obtener una lista infinita de esos valores. Sospecha que es posible que ya exista una función para ayudarlo ( faunque no específicamente para usted ).

Esa función sería de tipo (a -> a) -> a -> [a]si toma f 5o a -> (a -> a) -> [a]si toma 5 f(asumimos que la función es para tipos generales y no solo para Ints)

$ hoogle "a -> (a -> a) -> [a]"
Prelude iterate :: (a -> a) -> a -> [a]

sí, la función que necesitas ya existe y se llama iterate. lo usas por iterate func 5!

interfaz web

El resultado para el mismo ejemplo se puede encontrar aquí .


Encontrar las funciones de biblioteca estándar para lo que necesita se vuelve mucho más fácil una vez que comprende cómo pedirle a Hoogle lo que necesita.
ankh-morpork

57

La Programación de Graham Hutton en Haskell es concisa, razonablemente exhaustiva, y sus años de enseñanza Haskell realmente muestran. Casi siempre es con lo que recomiendo que empiecen las personas, independientemente de a dónde vayas desde allí.

En particular, el Capítulo 8 ("Analizadores funcionales") proporciona la base real que necesita para comenzar a tratar con las mónadas, y creo que es, con mucho, el mejor lugar para comenzar, seguido de Todo sobre las mónadas . (Sin embargo, con respecto a ese capítulo, tenga en cuenta las erratas del sitio web: sin embargo, no puede usar el doformulario sin alguna ayuda especial. Es posible que desee aprender primero sobre clases de tipos y resolver ese problema por su cuenta).

Esto rara vez se enfatiza a los principiantes de Haskell, pero vale la pena aprender desde el principio no solo sobre el uso de mónadas, sino sobre la construcción de la propia. No es difícil, y las personalizadas pueden hacer una serie de tareas bastante más simples.


55
Este es un libro totalmente subestimado (y respuesta). El capítulo sobre analizadores funcionales, seguido de un capítulo sobre IO, ninguno de los cuales menciona a las mónadas, realmente brilla como un elegante enfoque pedagógico.
michiakig


31

Sugeriría unirse al canal #haskell irc y hacer preguntas allí. Así aprendí Haskell. Si revisa Real World Haskell como se sugirió anteriormente, las respuestas en tiempo real a sus preguntas serán de gran ayuda. Muchas personas inteligentes en #haskell escriben Haskell por diversión y con fines de lucro, por lo que obtendrás una gran cantidad de comentarios. ¡Intentalo!


55
+1 - Para ser claros: no lo aprendas solo con el canal irc. Como en, no entre y pregunte "¿Cómo escribo un programa haskell? ¿Cómo agrego números?"
alternativa

Además de irc freenode, últimamente también hay una creciente discusión animada sobre haskell en los chats de Discord.
truthadjustr


19

Además, puedo recomendar Yet Another Haskell Tutorial como introducción.

Otro buen recurso de aprendizaje (probablemente en el nivel intermedio), que me ha ayudado mucho y que hasta ahora no he mencionado en las otras respuestas, es Typeclassopedia de Brent Yorgey , que se puede encontrar en The Monad Reader (Edición 13)

Está escrito en un estilo muy accesible y contiene (entre muchas otras cosas), los siguientes consejos introductorios:

Hay dos claves para la sabiduría de un experto pirata informático Haskell:

  1. Comprende los tipos.

  2. Obtenga una intuición profunda para cada clase de tipos y su relación con otras clases de tipos, respaldada por la familiaridad con muchos ejemplos.

El Monad Reader en sí mismo es un tesoro absoluto para programadores funcionales (no solo programadores Haskell).


14

Intenta escribir programas fáciles en él.

Puede encontrar tareas de muestra en varios libros de texto, probablemente.

No recomendaría seguir los libros de texto de Haskell / FP, solo intente hacer cosas simples con él: cálculos, manipulaciones de cadenas, acceso a archivos.

Después de resolver una docena, rompí el hielo :)

Después de eso, lea mucho sobre conceptos avanzados (mónadas, flechas, E / S, estructuras de datos recursivas), porque haskell es infinito y hay muchos de ellos.


14

Creo que realizar la característica de Haskell con ejemplos es la mejor manera de comenzar sobre todo.

http://en.wikipedia.org/wiki/Haskell_98_features

Aquí hay clases de tipos difíciles que incluyen mónadas y flechas

http://www.haskell.org/haskellwiki/Typeclassopedia

para problemas del mundo real y proyectos más grandes, recuerde estas etiquetas: GHC (compilador más utilizado), Hackage (libraryDB), Cabal (sistema de construcción), darcs (otro sistema de construcción).

Un sistema integrado puede ahorrarle tiempo: http://hackage.haskell.org/platform/

la base de datos del paquete para este sistema: http://hackage.haskell.org/

Wiki del compilador de GHC: http://www.haskell.org/haskellwiki/GHC

Después de Haskell_98_features y Typeclassopedia, creo que ya puedes encontrar y leer la documentación sobre ellos.

Por cierto, es posible que desee probar algunas extensiones de idiomas de GHC que pueden ser parte del estándar haskell en el futuro.

Esta es mi mejor manera de aprender Haskell. Espero que te pueda ayudar.


13

Sugiero que primero comience leyendo el tutorial de BONUS , y luego leyendo Real World Haskell (en línea de forma gratuita) . Únase al canal #Haskell IRC, en irc.freenode.com , y haga preguntas. Estas personas son absolutamente novatas y me han ayudado mucho con el tiempo. Además, aquí mismo, SO es un excelente lugar para obtener ayuda con cosas que no puede comprender. Trate de no desanimarse, una vez que haga clic, su mente se sorprenderá.

El tutorial de BONUS lo preparará y lo preparará para el emocionante viaje que trae Real World Haskell. ¡Te deseo suerte!


12

Si solo tiene experiencia con los lenguajes imperativos / OO, sugiero usar un lenguaje funcional más convencional como un trampolín. Haskell es realmente diferente y tienes que entender muchos conceptos diferentes para llegar a cualquier parte. Sugiero abordar primero un lenguaje de estilo ML (como, por ejemplo, F #).


Elm podría ser la más cercana, más útil y amigable para los principiantes de estas alternativas ...
Pedro Rolo

1
No estoy de acuerdo en pasar por una ruta temporal, como F #. Para mí, es como beber un vodka, debes tomarlo rápidamente. Más doloroso de esa manera, pero el placer también está ahí. Las rutas temporales, solo me generan más confusión.
truthadjustr

10

La primera respuesta es muy buena. Para llegar al nivel Experto, debes hacer un doctorado con algunos de los propios Expertos.

Le sugiero que visite la página de Haskell: http://haskell.org . Allí tiene una gran cantidad de material y muchas referencias a las cosas más actualizadas en Haskell, aprobadas por la comunidad de Haskell.


2
Lo siento, pero usar el argumento de doctorado aquí es como decir que tienes que tener un cuchillo de cocina de 300 $ para ser un buen chef. Incluso Simon Peyton Jones, el padre de Haskell, no tiene un doctorado. La práctica y la persistencia es lo que lleva a la experiencia tanto aquí como en cualquier otro campo.
Petras Purlys
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.