Translate
miércoles, 4 de noviembre de 2020
martes, 3 de noviembre de 2020
Elixir School
Elixir School es el primer destino para personas que buscan aprender y dominar el lenguaje de programación Elixir
Ya seas un veterano experimentado o esta es tu primera vez, vas a encontrar lo que necesitas en las lecciones y en los recursos auxiliares
Mediante el trabajo duro de voluntarios Elixir School ha sido traducido a muchos idiomas. Algunas de estas traducciones incluyen: Việt ngữ, 简体中文, 繁體中文, English, Slovenčina, 日本語, Polski, Português, Русском, Bahasa Indonesia, Bahasa Melayu, Українською, 한국어, Italiano, Deutsch, বাংলা, Türkçe, y ภาษาไทย.
Te damos la bienvenida y te motivamos a continuar haciendo Elixir School grandioso involucrándote en elixirschool/elixirschool!
De esta manera se presenta Elixir school que es un excelente sitio para comenzar con Elixir.
Y sin más dejo link: https://elixirschool.com/es/
lunes, 2 de noviembre de 2020
Tipos con Clase parte 5
Num: números, con muchas subclases para tipos específicos de números.
Read: tipos que se pueden "leer desde" una cadena.
Show: tipos que se pueden "mostrar a" una cadena.
Eq: tipos para los que se define el operador de igualdad ==.
Ord: tipos para los que puede hacer comparaciones como <,>, etc.
Enum: tipos donde los valores se pueden enumerar en secuencia; esto se usa, por ejemplo, en la notación [1..n] y ′ a ′ .. ′ z ′.
*Main> [1..10]
[1,2,3,4,5,6,7,8,9,10]
*Main> ['a'..'z']
"abcdefghijklmnopqrstuvwxyz"
Tipos con Clase parte 4
Seguimos con Type class.
Algunos valores se pueden "mostrar", pero no todos.
Por ejemplo, en general es imposible mostrar una función.
Por lo tanto, debemos usar type class
show::Show a → a→String
Definición de su propia instancia de Show
data Foo = Bar | Baz
Podríamos querer nuestra propia representación de cadena :
instance Show Foo where
show Bar = "it is a bar"
show Baz = "this is a baz"
Recordemos que cuando ingresa una expresión exp en ghci, imprime showexp. Entonces podemos probar nuestra extraña declaración de instancia:
*Main> Bar
it is a bar
*Main> Baz
this is a baz
deriving nos permite indicar que "implementa" Show o otro data type :
data Foo2 = Bar2 | Baz2
deriving (Read, Show)
Haskell definirá automáticamente una instancia de show para Foo2, usando la definición obvia:
*Main> Bar2
Bar2
*Main> Baz2
Baz2
domingo, 1 de noviembre de 2020
Tipos con Clase parte 3
Seguimos con type class
Haskell proporciona varias type class estándar. Echemos un vistazo a Num.
Num es la clase de tipos numéricos.
Aquí está (en parte) su declaración de clase:
class Num a where
(+), (-), (*) :: a -> a -> a
Hay muchos tipos numéricos; dos de ellos son Int y Double.
Hay funciones monomórficas primitivas que realizan operaciones aritméticas en estos tipos (estos no son los nombres reales):
addInt, subInt, mulInt :: Int -> Int -> Int
addDbl, subDbl, mulDbl :: Double -> Double -> Double
instance Num Int where
(+) = addInt
(-) = subInt
(*) = mulInt
instance Num Double where
(+) = addDbl
(-) = subDbl
(*) = mulDbl
Hay algunas operaciones (suma) que son válidas para todos los tipos numéricos. Hay algunos otros (por ejemplo, funciones trigonométricas) que son válidos solo para algunos tipos numéricos.
Por lo tanto, existe una rica jerarquía de subclases, que incluyen :
Integral: clase de tipos numéricos que representan valores enteros, incluidos Int, Integer y más.
Fraccional: clase de tipos que pueden representar fracciones.
Floating: clase que contiene Float, Double, etc.
Bounded: clase de tipos numéricos que tienen un elemento mínimo y máximo.
Bits: clase de tipos donde puede acceder a la representación como una secuencia de bits, útil para la programación de sistemas y el diseño de circuitos digitales.
Si deseamos profundizar en clases y tipos numéricos, podemos consultar la documentación de Haskell.
Tipos con Clase parte 2
Seguimos con type class
Haskell tiene algunas Type Classes estándar que se definen en el Preludio estándar.Pero también podemos definir el tuyo propio.
Supongamos que estamos computando con colores. Aquí hay un tipo y un par de funciones.
data Bright = Blu | Red
deriving (Read, Show)
darkBright :: Bright -> Bool
darkBright Blue = True
darkBright Red = False
lightenBright :: Bright -> Bright
lightenBright Blue = Red
lightenBright Red = Red
Ahora, suponga que tenemos un tipo diferente que necesita funciones similares.
data Pastel = Turquoise | Tan
deriving (Read, Show)
darkPastel :: Pastel -> Bool
darkPastel Turquoise = True
darkPastel Tan = False
lightenPastel :: Pastel -> Pastel
lightenPastel Turquoise = Tan
lightenPastel Tan = Tan
Ambos tipos de colores tienen funciones para decidir si es oscuro o claro.
Podemos definir una clase Color y sus funciones correspondientes.
class Color a where
dark :: a -> Bool
lighten :: a -> a
Esto dice :
- El color es una clase de tipo
- La variable de tipo a representa un tipo particular que está en la clase Color
- Para cualquier tipo a en Color, hay dos funciones que puede usar: oscuro y claro, con los tipos especificados.
Una declaración de instancia dice que un tipo es miembro de una clase de tipo.
Cuando declaras una instancia, necesitas definir las funciones de clase.
A continuación se indica que el tipo Bright está en la clase Color y, en ese caso, la función oscura es en realidad darkBright.
instance Color Bright where
dark = darkBright
lighten = lightenBright
De manera similar, podemos declarar que Pastel está en Color, pero tiene diferentes funciones para implementar las operaciones de la clase.
instance Color Pastel where
dark = darkPastel
lighten = lightenPastel
Tipos con Clase
Type class son una forma de sobrecargar funciones u operadores al imponer restricciones al polimorfismo.
Por ejemplo:
(+) :: a -> a -> a
no está bien porque queremos restringir la suma de números.
Igualmente,
(<) :: a -> a -> Bool
no está bien porque no está claro a priori cómo comparar con tipos arbitrarios.
Para abordar este problema, Haskell proporciona Type class. Estos restringen el polimorfismo. Por ejemplo:
(+) :: Num a => a -> a -> a
dice que el tipo a debe ser numérico, y
(<) :: Ord a => a -> a -> Bool
dice que debe ser ordenable.
Y eso es todo! listo, pero pero puedo crear mi propio type class? Lucho, por supuesto viejo... pero lo vamos a ver en el próximo post.
viernes, 30 de octubre de 2020
Zip y unzip en python
Zip es una función útil que le permite combinar dos listas fácilmente. Como un cierre.
Después de llamar a zip,obtenemos un iterador. Para ver el contenido envuelto dentro, primero debemos convertirlo en una lista.
Ejemplo:
first_name = ['Joe','Earnst','Thomas','Martin','Charles']
last_name = ['Schmoe','Ehlmann','Fischer','Walter','Rogan','Green']
age = [23, 65, 11, 36, 83]
print(list(zip(first_name,last_name, age)))
# Output
#
# [('Joe', 'Schmoe', 23), ('Earnst', 'Ehlmann', 65), ('Thomas', 'Fischer', 11), ('Martin', 'Walter', 36), ('Charles', 'Rogan', 83)]
Una ventaja del zip es que mejora la legibilidad de los bucles for.
Por ejemplo, en lugar de necesitar varias entradas, solo necesita una lista zip para el siguiente bucle for:
first_name = ['Joe','Earnst','Thomas','Martin','Charles']
last_name = ['Schmoe','Ehlmann','Fischer','Walter','Rogan','Green']
age = [23, 65, 11, 36, 83]
for first_name, last_name, age in zip(first_name, last_name, age):
print(f"{first_name} {last_name} is {age} years old")
# Output
#
# Joe Schmoe is 23 years old
# Earnst Ehlmann is 65 years old
# Thomas Fischer is 11 years old
# Martin Walter is 36 years old
# Charles Rogan is 83 years old
También podemos usar la función zip para abrir el cierre o hacer unzip . Esta vez, necesitamos la entrada de una lista con un asterisco antes.
Las salidas son listas separadas.
full_name_list = [('Joe', 'Schmoe', 23),
('Earnst', 'Ehlmann', 65),
('Thomas', 'Fischer', 11),
('Martin', 'Walter', 36),
('Charles', 'Rogan', 83)]
first_name, last_name, age = list(zip(*full_name_list))
print(f"first name: {first_name}\nlast name: {last_name} \nage: {age}")
# Output
# first name: ('Joe', 'Earnst', 'Thomas', 'Martin', 'Charles')
# last name: ('Schmoe', 'Ehlmann', 'Fischer', 'Walter', 'Rogan')
# age: (23, 65, 11, 36, 83)
miércoles, 28 de octubre de 2020
apuntes.de
Quiero recomendarles este sitio que esta en español y tienen varios libros gratuitos sobre tecnología. Que temas pueden encontrar??
- AWS (Fundamentos Prácticos)
- AWS (Cloud Practitioner CLF-C01)
- AWS (Certificación CSSA)
- Bitcoins (Criptomonedas)
- Código Limpio (Desarrollo Ágil de Software)
- Docker (Certificación DCA)
- Electron (Desarrollo de aplicaciones de escritorio con JavaScript)
- Emprendimiento (Creación de Startups)
- Golang (Desde Cero)
- Ionic (Desarrollo de aplicaciones multiplataforma con JavaScript)
- Linux (Certificación LPI)
- NodeJS (Desde Cero)
- NodeJS (Desarrollo Web)
- Python (Certificación PCEP)
- Ruby (Curso en Español desde Cero)
- Entrenamiento SEO (Search Engine Optimizacion)
- Fundamentos de SEO (Search Engine Optimization)
sin más : https://apuntes.de
martes, 27 de octubre de 2020
Tour of Scala
Dejo link: https://tourofscala.com/
domingo, 25 de octubre de 2020
Introducción al cálculo Lambda
El cálculo lambda fue desarrollado en la década de 1930 por Alonzo Church (1903-1995), uno de los principales desarrolladores de lógica matemática. El cálculo lambda fue un intento de formalizar funciones como medio de computación.
Un avance importante (realmente el mayor) en la teoría de la computabilidad fue la prueba de que el cálculo lambda y la máquina de Turing tienen exactamente el mismo poder computacional. Esto llevó a la tesis de Church: que el conjunto de funciones que son efectivamente computables es exactamente el conjunto computable por la máquina de Turing o el cálculo lambda.
La tesis se fortaleció cuando varios otros sistemas de computación matemática (Problema posterior a la correspondencia y otros) también demostraron ser equivalentes al cálculo lambda.
El punto es que el conjunto de funciones efectivamente computables parece ser una realidad fundamental, no solo una peculiaridad de cómo se definió la {máquina de Turing, cálculo lambda}.
El cálculo lambda ha resultado capturar dos aspectos de una función:
- Un objeto matemático (conjunto de pares ordenados de dominio y rango), y
- Una máquina de caja negra abstracta que toma una entrada y produce una salida.
El cálculo lambda es fundamental para la semántica denotacional, la teoría matemática de lo que significan los programas de computadora.
Los lenguajes de programación funcional se desarrollaron con el objetivo explícito de convertir el cálculo lambda en un lenguaje de programación práctico.
El compilador ghc Haskell opera (1) desechando el programa fuente, (2) transformando el programa en una versión del cálculo lambda llamado Sistema F, y (3) traduciendo el Sistema F al lenguaje de máquina usando reducción de grafos.
Trabajaremos con el cálculo lambda básico “enriquecido” con algunas constantes y funciones primitivas (estrictamente hablando, eso no es necesario).
El lenguaje tiene constantes, variables, aplicaciones y funciones.
exp = const
| var
| exp exp
| \ var -> exp
Cada aparición de una variable en una expresión está ligada o es libre.
En ∖x → x + 1, la ocurrencia de x en x + 1 está limitada por ∖x.
En y ∗ 3, la ocurrencia o y es libre. Debe definirse en otro lugar, quizás como una definición global.
En general, una aparición de una variable está vinculada si hay alguna expresión lambda adjunta que la vincula; si no hay enlace lambda, entonces la ocurrencia es libre.
Debemos tener cuidado: la primera aparición de a es libre pero la segunda aparición está vinculada.
a + (\ a -> 2 ^ a) 3 -> a + 2 ^ 3
Ser libre o vinculada es una propiedad de la ocurrencia de una variable, ¡no de la variable en sí!
La computación en el cálculo lambda se realiza utilizando tres reglas de conversión.
Las reglas de conversión le permiten reemplazar una expresión por otra ("igual").
Algunas conversiones simplifican una expresión; estos se llaman reducciones.
Conversión alfa : La conversión alfa le permite cambiar el nombre de un parámetro de función de manera consistente. ¡Pero no puede cambiar las variables libres con la conversión alfa!
La definición detallada de conversión alfa es un poco complicada, porque debe tener cuidado de ser coherente y evitar la "captura de nombres". No nos preocuparemos por los detalles en este momento.
(\ x -> x + 1) 3
(\ y -> y + 1) 3
Conversión beta : La conversión beta es el "caballo de batalla" del cálculo lambda: define cómo funcionan las funciones.
Para aplicar una expresión lambda a un argumento, se toma el cuerpo de la función y se reemplaza cada aparición enlazada de la variable con el argumento.
(\ x -> exp1) exp2se evalúa como exp1 [exp2 / x]
Ejemplo:
(\ x -> 2 * x + g x) 42
se evalúa como 2 ∗ 42 + g 42
Conversión ETA : Eta conversión dice que una función es equivalente a una expresión lambda que toma un argumento y aplica la función al argumento.
(\ x -> f x)
es equivalente a f
Ejemplo (recuerde que (∗ 3) es una función que multiplica su argumento por 3)
(\ x -> (* 3) x)
es equivalente a (∗ 3)
Intente aplicar ambos a 50:
(\ x -> (* 3) x) 50
es lo mismo que (∗ 3) 50
Existe un uso común de la conversión Eta. Supongamos que tenemos una definición como esta:
f x y = g y
Esto se puede reescribir de la siguiente manera:
f = \ x -> (\ y -> g y)
f = \ x -> g = f x = g
Por tanto, las siguientes dos definiciones son equivalentes:
f x y = g y
f x = g
En efecto, dado que el último argumento en ambos lados de la ecuación es el mismo (y), se puede “factorizar”.
Y listo, no quiero profundizar en detalles matemáticos, pero sin duda que esta teoría influyo mucho el mundo de los lenguajes y quiero compartir una imagen que encontré y describe como ha llegado esta teoría al mainstream de los lenguajes y gracias a quienes :
viernes, 23 de octubre de 2020
Cómo y por qué Twitter usa Scala ?
Twitter usa Scala, si! hace mucho. Scala es un lenguaje de programación que combina rasgos de lenguajes orientados a objetos. y lenguajes funcionales con miras a soportar mejor la concurrencia en software a gran escala.
¿Por qué utilizar Scala? Lo que necesitaba a medida que Twitter crecía era procesos pesados de larga ejecución, cola de mensajes, capas de almacenamiento en caché para realizar 20.000 operaciones por segundo.
¿cuáles fueron los criterios para elegir Scala? Bueno, primero ¿es rápido, divertido y bueno para un proceso de larga duración? ¿Tiene funciones avanzadas? ¿Puede ser productivo rápidamente? Los desarrolladores del lenguaje en sí tenían que ser accesibles para nosotros.
¿Y Scala resultó ser rápido? Bueno, ¿cuál es tu definición de rápido? Casi tan rápido como Java. No tiene que ser tan rápido como C o Assembly. Python no es significativamente más rápido que Ruby. Querían hacer más con menos máquinas, aprovechando mejor la concurrencia; quería que se compilara para que no quemara la CPU haciendo las cosas incorrectas.
Es muy divertido trabajar en Scala; sí, puede escribir código serio, similar a Java, cuando empiece. Más tarde, puede escribir código Scala que casi se parece a Haskell. Puede ser muy idiomático, muy funcional, hay mucha flexibilidad ahí.
Y es rápido. El principal desarrollador de lenguaje de Scala trabajó en la JVM en Sun. Cuando comenzó Java, era claramente un gran lenguaje, pero la máquina virtual era lenta. La JVM se ha llevado a la era moderna y no nos lo pensamos dos veces antes de usarla.
Scala puede tomar prestadas bibliotecas de las bibliotecas de Java; está compilando en código de bytes de Java, y todo está llamando de un modo que es realmente eficiente. No nos hemos encontrado con ninguna dependencia de biblioteca que cause problemas. Podemos contratar personas con Java y pueden hacerlo bastante bien.
La gran teoría unificada de Scala es que combina programación orientada a objetivos (OOP) y programación funcional (FP). El objetivo de Scala es esencialmente decir que OOP y FP no tienen que ser estos mundos separados. Es algo zen, y no lo entiendes cuando empiezas. Es realmente poderoso; es bueno tener un lenguaje con una tesis, en lugar de tratar de atraer a todos los programadores. Scala está tratando de resolver un problema intelectual específico.
Tiene métodos que toman cualquier cosa entre una cadena y varios puntos en la cadena de herencia de una cadena. La sintaxis es más flexible que la de Java; es muy legible por humanos, ya que puede omitir un período entre las llamadas al método para que parezca una serie de palabras. Su programa puede hacer buenas declaraciones declarativas sobre la lógica de lo que está tratando de hacer.
Con Scala, también puede usar rasgo o traits. Esto es útil porque, por supuesto, tiene preocupaciones transversales en su aplicación. Por ejemplo, todos los objetos deben poder registrar cosas, pero no quieres que todo se extienda desde una clase de registrador, eso es una locura. Con Scala, puede usar un rasgo para introducirlo directamente y puede agregar tantos rasgos como desee a una clase u objeto determinado.
Puedes elegir entre mutabilidad e inmutabilidad. Esto puede resultar peligroso. 9 de cada 10 veces usa variables inmutables cuando desea previsibilidad, especialmente cuando tiene cosas ejecutándose al mismo tiempo. Pero Scala confía en el programador para la mutabilidad cuando lo necesita.
Scala tiene el concepto de valores perezosos; se puede decir lazy val x = una función realmente complicada. Eso no se calculará hasta el último segundo, cuando necesite ese valor. Esto es bonito.
Pattern matching también es buena. Le permite sumergirse en una estructura de datos para que pueda, por ejemplo, explotar una colección que coincida con una matriz con "2" como tercer elemento. Puede dividir cadenas y expresiones regulares, y puede combinar grupos de patrones con expresiones regulares.
Una característica extraña que es realmente útil es la capacidad de usar literales XML, de modo que pueda hacer algo igual a un literal XML, como si el literal XML fuera una cadena. No tienes que importar Sax o alguna biblioteca XML.
Cuando la gente lee sobre Scala, casi siempre es en el contexto de la concurrencia. La simultaneidad la puede resolver un buen programador en muchos lenguajes, pero es un problema difícil de resolver. Scala tiene una biblioteca de Actores, Akka, que se usa comúnmente para resolver problemas de concurrencia, y hace que ese problema sea mucho más fácil de resolver.
Un actor es un objeto que tiene un buzón; pone en cola los mensajes y los trata en un bucle, y puede dejar un mensaje en el suelo cuando no sabe qué hacer con él.
Puede modelar la concurrencia como mensajes, una unidad de trabajo, enviados a los actores, lo cual es realmente bueno. Es como usar un sistema de cola. También puede usar Java.util.concurrency, Netty y Apache Mina, colocándolo directamente. Puede reescribir la implementación de Actor, y algunas personas han ido tan lejos como para lanzar sus propias bibliotecas de memoria transaccional de software.
La interoperabilidad de Java es una gran, gran victoria. Hay diez años de grandes bibliotecas, cosas como Jodatime. Usamos mucho Hadoop y ha sido fácil conectar Scala a las bibliotecas de Hadoop. Usamos Thrift, sin tener que parchearlo; utilizamos bibliotecas de Apache Commons y de Google.
En el mundo empresarial, una arquitectura orientada a servicios no es nueva, pero en la Web 2.0 es una ciencia nueva y loca. Con PHP o Ruby on Rails, cuando necesite más funcionalidad, simplemente incluya más complementos y bibliotecas, y los inserte todos en el servidor. El resultado es una bola de barro gigante.
Entonces, cualquier cosa que tenga que hacer un trabajo pesado en nuestra pila será un servicio independiente. Podemos probarlo de forma independiente, es una buena forma de descomponer nuestra arquitectura.
¿Qué servicios de Twitter funcionan con Scala? Tienen un sistema de colas llamado Kestrel. Utiliza una versión mejorada del protocolo mem-cache. Originalmente se escribio en Ruby, pero debido a que Ruby es un lenguaje dinámico, el servicio comenzó a mostrar sus puntos débiles de rendimiento.
Flock usan para almacenar grafos social, como una lista desnormalizada de identificadores de usuario. No es una base de datos de grafos, por lo que no puede realizar recorridos aleatorios a lo largo del grafo. Pero es excelente para almacenar rápidamente conjuntos desnormalizados de ID de usuario y hacer intersecciones. Estan realizando 20.000 operaciones por segundo en ese momento, respaldadas por un esquema MySQL diseñado para mantener tanto como sea posible en la memoria. Ha sido muy eficiente, no se necesitan muchos servidores.
El servicio de búsqueda de personas está impulsada por un servicio creado por Scala que se llama Hawkwind. Es un grupo de objetos de usuario que Hadoop arroja, donde la solicitud se distribuye en varias máquinas y luego se vuelve a unir.
miércoles, 21 de octubre de 2020
Quien utiliza Haskell??
La programación funcional (en particular Haskell) es utilizada por un número creciente de empresas en la actualidad, incluidas algunas grandes multinacionales.
Hay listas de empresas que utilizan Haskell en el sitio web de Haskell y en Quora. Algunas companias destacadas son Facebook, IBM, Twitter, AT&T, Bank of America, Barclays Capital, NVIDIA y Microsoft.
Facebook utiliza Haskell en varios proyectos, por ejemplo Lucha contra el spam con Haskell.
Galois ha sido un usuario y promotor activo de Haskell durante más de una década. Esta charla presenta tres estudios de caso de algunos de sus proyectos.
The New York Times tiene una agradable charla sobre Haskell en la sala de redacción.
lunes, 19 de octubre de 2020
QuickCheck: prueba automática programas Haskell
QuickCheck es una biblioteca para pruebas aleatorias de propiedades de programas.
El programador proporciona una especificación del programa, en forma de propiedades que las funciones deben satisfacer, y QuickCheck luego prueba que las propiedades se cumplen en una gran cantidad de casos generados aleatoriamente.
Las especificaciones se expresan en Haskell, utilizando combinadores proporcionados por QuickCheck.
QuickCheck proporciona combinadores para definir propiedades, observar la distribución de los datos de prueba y definir generadores de datos de prueba.
veamos un ejemplo, primero definamos una propiedad :
prop_RevRev xs = reverse (reverse xs) == xs
where types = xs::[Int]
y luego a probar la propiedad
Main> quickCheck prop_RevRev
OK, passed 100 tests.
Y si fallará nos mostraría todas las veces que fallo :
Main> quickCheck prop_RevId
Falsifiable, after 1 tests:
[-3,15]
Y listo, tenemos una comprobación rapida y fácil para nuestros programas.
Dejo link: http://www.cse.chalmers.se/~rjmh/QuickCheck/
domingo, 18 de octubre de 2020
Currying en Haskell
Si tenemos esta firma de función :
f :: X -> Y -> Z -> A
La flecha "->" es asociativa a la derecha, por lo que es lo mismo que:
f :: X -> (Y -> (Z -> A))
Lo que esto significa es que podemos considerar f como una función con un solo argumento de tipo X que devuelve una función de tipo Y-> Z-> A.
La técnica de reescribir una función de múltiples argumentos en una secuencia de funciones con un solo argumento se llama currización. Podemos ilustrar esto mejor usando una función lambda:
\ x y z -> ...
\ x -> (\ y z -> ...)
\ x -> (\ y -> (\ z -> ...))
El nombre "curry", es una referencia al lógico Haskell Curry. El concepto en realidad fue propuesto originalmente por otro lógico, Moses Schönfinkel, pero su nombre no era tan pegadizo.
La aplicación parcial significa que no necesitamos proporcionar todos los argumentos a una función, para aplicar la función. Por ejemplo, dado
sq x y = x*x+y*y
Observamos que la aplicación de la función se asocia a la izquierda, por lo que se cumple la siguiente equivalencia
sq x y = (sq x) y
Por tanto, podemos crear una función especializada mediante la aplicación parcial de x:
sq4 = sq 4 -- = \y -> 16+y*y
sq4 3 -- = (sq 4) 3 = sq 4 3 = 25
Es por eso que puedes escribir cosas como:
dobles = mapa (* 2) [1 ..]