Ojo! se que no se ve, solo tienen que hacer click en la imagen.
Translate
martes, 28 de octubre de 2014
Que son las aplicaciones Reactivas?
Una pequeña infografia que describe muy bien los principios de las aplicaciones reactivas:
sábado, 25 de octubre de 2014
Primeros pasos en Qt: Emitir una señal
En los post anteriores estuvimos viendo el mecanismo de signals y slots que permitían manejar una señal emitida por un componente.
Además estuvimos haciendo una ventana de dialogo que permitía, para buscar un texto determinado. Este dialogo no puede hacer la acción porque no conoce el texto donde se debe realizar la búsqueda.
Resumiendo:
connect(ventanaBusqueda, SIGNAL(aceptar(QString)), this, SLOT(busqueda(QString));
En la ventana padre debemos conectar nuestra ventana de búsqueda con el proceso de búsqueda. Noten el detalle de que indicamos el tipo de parámetro de las funciones.
Si probamos esto no va a suceder nada porque nuestra pantalla de dialog no emite la señal, veamos como podemos hacer esto:
emit aceptar(text)
En el botón del dialog debemos emitir la señal. Con emit emitimos una señal, en este caso emitimos la señal aceptar y le pasamos un testo como parámetro.
Dejo link:
http://qt-project.org/doc/qt-4.8/signalsandslots.html
Además estuvimos haciendo una ventana de dialogo que permitía, para buscar un texto determinado. Este dialogo no puede hacer la acción porque no conoce el texto donde se debe realizar la búsqueda.
Resumiendo:
- Tenemos 2 ventanas una con todo el texto donde se debe realizar la búsqueda y la otra que permite ingresar el texto a buscar.
- Por lo tanto la ventana main o padre debe realizar la búsqueda.
- La ventana de dialog debe enviar una señal con el texto ingresado.
- Esta señal va a ser procesada por la ventana main que realizará la búsqueda.
connect(ventanaBusqueda, SIGNAL(aceptar(QString)), this, SLOT(busqueda(QString));
En la ventana padre debemos conectar nuestra ventana de búsqueda con el proceso de búsqueda. Noten el detalle de que indicamos el tipo de parámetro de las funciones.
Si probamos esto no va a suceder nada porque nuestra pantalla de dialog no emite la señal, veamos como podemos hacer esto:
emit aceptar(text)
En el botón del dialog debemos emitir la señal. Con emit emitimos una señal, en este caso emitimos la señal aceptar y le pasamos un testo como parámetro.
Dejo link:
http://qt-project.org/doc/qt-4.8/signalsandslots.html
jueves, 23 de octubre de 2014
Java VS Properties
Les quiero dejar un link de un tema muy interesante, las properties en Java. Yo recuerdo que Delphi (Object Pascal) hace 15 años más o menos ya tenia properties. Las properties te permitían acceder a propiedades privadas sin romper la encapsulación y sin escribir métodos para acceder.
Es una lucha entre el tedio de escribir métodos que el 90% de la veces son iguales, y a nadie le importa contra el encapsulamiento.
Dejo el link: http://betterunspoken.com/java-vs-properties-why-we-should-be-sad-about-getters-setters/?utm_source=google+plus&utm_medium=link&utm_campaign=java-getter-setter-post
miércoles, 22 de octubre de 2014
Compiladores e interpretes: teoría y práctica
Quiero compartir este excelente libro sobre compiladores e interpretes totalmente gratuito y en español.
Dejo link:
http://www.infotutoriales.info/2014/10/compiladores-e-interpretes-teoria-y.html
Node.js vs Play
Un muy buen resumen sobre las diferencias de estos Frameworks y muchas cosas que no sabia, por ejemplo que coursera esta hecho en play.
sábado, 18 de octubre de 2014
Estructuras de datos recursivas en Haskell y Scala, segunda parte
Vamos a ejemplificar lo que vimos en el post anteríor con un ejemplo de árbol binario de búsqueda. Si no estás familiarizado con los árboles binarios de búsqueda de otros lenguajes como C, aquí tienes una explicación de lo que son: un elemento apunta a otros dos elementos, uno esta a la izquierda y otro a la derecha. El elemento a la izquierda es más pequeño y el segundo es más grande. Cada uno de estos dos elementos puede apuntar a otros dos elementos (o a uno o a ninguno). En efecto, cada elemento tienen sus propios sub-árboles. Lo bueno de los árboles binarios de búsqueda es que sabemos que todos los elementos que están en el sub-árbol de la izquierda de, 5, por ejemplo, son menores que 5. Lo elementos que están en el sub-árbol de la derecha son mayores. Así que si estamos buscando el elemento 8 en nuestro árbol, empezamos comparándolo con 5, como vemos que es menor que 5, nos vamos al sub-árbol de la derecha. Ahora estaríamos en 7, como es menor que 8 continuaríamos hacia la derecha. De esta forma encontraríamos el elemento en tres pasos. Si estuviéramos usando una lista (o un árbol no balanceado), nos hubiera costado unos 7 pasos encontrar el 8.
Los conjuntos y diccionario de Data.Set y Data.Map de Haskell están implementandos utilizando árboles, solo que en lugar de árboles binarios de búsqueda, utilizan árboles binarios de búsqueda balanceados, de forma que estén siempre balanceados. Ahora implementaremos simplemente árboles binarios de búsqueda normales.
Vamos a decir que: un árbol es o bien un árbol vacío o bien un elemento que contiene un elemento y otros dos árboles. Tiene pinta de que va a encajar perfectamente con los tipos de datos algebraicos.
data Tree a = EmptyTree | Node a (Tree a) (Tree a) deriving (Show, Read, Eq)
Esto en Scala podríamos implementarlo con Clases Case, o con herencia también funcionaría pero voy a utilizar Clases Case:
abstract class Tree
case class EmptyTree extends Tree
case class Node (nro: Int, left: Tree, rigth: Tree) extends Tree
En lugar de construir manualmente un árbol, vamos a crear una función que tome un elemento y un árbol e inserte dicho elemento en su posición adecuada dentro del árbol. Hacemos esto comparando el elemento que queremos insertar con la raíz del árbol y si es menor, vamos a la izquierda y si no a la derecha. Hacemos lo mismo para coda nodo siguiente hasta que alcanzamos un árbol vacío. Cuando lo hagamos simplemente insertamos el elemento en lugar del árbol vacío.
En lenguajes como C, realizamos esta tarea modificando los punteros y valores del árbol. En Haskell, no podemos modificar nuestro árboles, así que tenemos que crear un nuevo sub-árbol cada vez que decidamos si vamos a la derecha o a la izquierda y al final la función de inserción devolver un árbol completamente nuevo, ya que Haskell no tiene el concepto de puntero. Así pues la declaración de tipo de nuestra función será algo como a -> Tree a - > Tree a. Toma un elemento y un árbol y devuelve un nuevo árbol que posee en su interior dicho elemento.
Aquí tienes dos funciones. Una de ellas es una función auxiliar para crear un árbol unitario (que solo contiene un elemento) y la otra es una función que inserta elementos en un árbol.
singleton :: a -> Tree a
singleton x = Node x EmptyTree EmptyTree
treeInsert :: (Ord a) => a -> Tree a -> Tree a
treeInsert x EmptyTree = singleton x
treeInsert x (Node a left right)
| x == a = Node x left right
| x < a = Node a (treeInsert x left) right
| x > a = Node a left (treeInsert x right)
La función singleton es forma rápida de crear un árbol que contenga un elemento y dos sub-árboles vacíos. En la función de inserción, tenemos como primer patrón el caso base. Si hemos alcanzado un sub-árbol vacío, esto significa que estamos donde queríamos y en lugar de un árbol vacío, queremos un árbol unitario que contenga el elemento a insertar. Si no estamos insertando el elemento en un árbol vacío tenemos que comprobar varias cosas. Primero, si el elemento que vamos a insertar es el mismo que la raíz del sub-árbol, simplemente devolvemos el árbol como estaba. Si es menor, devolvemos un árbol que tenga la misma raíz, el mismo sub-árbol derecho pero en lugar de su sub-árbol izquierdo, ponemos el árbol que va a contener dicho elemento. Lo mismo ocurre (pero en sentido contrario) para los valores que son mayores que el elemento raíz.
En Scala podemos hacer un método que con pattern matching saber que clase es:
def treeInsert(nro:Int, tree: Tree) : Tree = tree match {
case EmptyTree => Node (nro, EmptyTree(), EmptyTree())
case Node (nroTree, left, right) => if (nroTree == nro) Node (nro, left, right)
else if (nro < nroTree) Node (nroTree, treeInsert(nro, left), right)
else Node (nroTree, left, treeInsert(nro, right))
}
A continuación vamos a crear una función que compruebe si un elemento pertence a un árbol. Primero vamos a definir el caso base. Si estamos buscando un elemento en un árbol vacío, obviamente el elemento no está ahí. Vale, fíjate que esto es básicamente lo mismo que el caso base de la búsqueda en listas: si estamos buscando un elemento en una lista vacía, obviamente el elemento no está ahí. De todos modos, si no estamos buscando el elemento en un árbol vacío, entonces tenemos que hacer varias comprobaciones. Si el elemento que estamos buscando es el elemento raíz ¡Genial! ¿Y si no lo es? Bueno, tenemos la ventaja de que sabemos que todos los elementos menores que la raíz están en el sub-árbol izquierdo. Así que si el elemento que estamos buscando es menor que la raíz, comprobamos si el elemento está en el sub-árbol izquierdo. Si es mayor, comprobamos el sub-árbol derecho.
treeElem :: (Ord a) => a -> Tree a -> Bool
treeElem x EmptyTree = False
treeElem x (Node a left right)
| x == a = True
| x < a = treeElem x left
| x > a = treeElem x right
En Scala:
def treeElem(nro:Int, tree: Tree) : Boolean = tree match {
case EmptyTree => false
case Node (nroTree, left, right) => if (nroTree == nro) true
else if (nro < nroTree) treeElem(nro, left)
else treeElem(nro, right)
}
¡Vamos a divertirnos con nuestro árboles! En lugar de construir manualmente un árbol (aunque podríamos), usaremos un pliegue para construir un árbol a partir de una lista. Recuerda, casi cualquier cosa que recorra una lista elemento a elemento y devuelve alguna especie de valor puede ser implementado con un pliegue. Empezaremos con un árbol vacío y luego recorreremos la lista desde la derecha e iremos insertando elementos a nuestro árbol acumulador.
ghci> let nums = [8,6,4,1,7,3,5]
ghci> let numsTree = foldr treeInsert EmptyTree nums
ghci> numsTree
Node 5 (Node 3 (Node 1 EmptyTree EmptyTree) (Node 4 EmptyTree EmptyTree)) (Node 7 (Node 6 EmptyTree EmptyTree) (Node 8 EmptyTree EmptyTree))
En este foldr, treeInsert es la función de pliegue (toma un árbol y un elemento de la lista y produce un nuevo árbol) y EmptyTree es el valor inicial. Por supuesto, nums es la lista que estamos plegando.
No es muy legible el árbol que se muestra por la consola, pero si lo intentamos, podemos descifrar su estructura. Vemos que el nodo raíz es 5 y luego tiene dos sub-árboles, uno que tiene como elemento raíz a 3, y otro a 7.
ghci> 8 `treeElem` numsTree
True
ghci> 100 `treeElem` numsTree
False
ghci> 1 `treeElem` numsTree
True
ghci> 10 `treeElem` numsTree
False
Vamos que comprobar la pertenencia de un elemento a un árbol funciona perfectamente. Genial.
Como puede ver los tipos de datos algebraicos en Haskell son un concepto muy interesante a la vez potentes. Podemos utilizarlos desde para representar valores booleanos hasta enumeraciónes de los días de la semana, e incluso árboles binarios de búsquedas.
Estructuras de datos recursivas en Haskell y Scala
Una estructura de datos en Haskell o una clase en java o scala puede contener atributos esos atributos tienen un tipo determinado si ese tipo es igual a la clase contenedora tenemos una estructura recursiva.
Piensa en la lista en Haskell [5]. Es lo mismo que 5:[]. A la izquierda del : hay un valore, y a la derecha hay una lista. En este caso, una lista vacía. ¿Qué pasaría con la lista [4,5]? Bueno, es lo mismo que 4:(5:[]). Si miramos el primer :, vemos que también tiene un elemento a su izquierda y una lista a su derecha (5:[]). Lo mismo sucede para la lista 3:(4:(5:6:[])), que también podría escribirse como 3:4:5:6:[] (ya que : es asociativo por la derecha) o [3,4,5,6].
Podemos decir que una lista es o bien una lista vacia o bien un elemento unido con un : a otra lista (que puede ser una lista vacía o no).
Podemos usar los tipo de datos algebraicos para implementar nuestra propia lista:
data List a = Empty | Cons a (List a) deriving (Show, Read, Eq, Ord)
Se lee de la misma forma que se leía nuestra definición de lista en un párrafo anterior. Es o bien una lista vacía o bien una combinación de un elemento y otra lista. Si estás confundido con esto, quizás te sea más fácil entenderlo con la sintaxis de registro:
data List a = Empty | Cons { listHead :: a, listTail :: List a} deriving (Show, Read, Eq, Ord)
Puede que también estes confundido con el constructor Cons. Cons es otra forma de decir :. En realidad, en las listas, : es un constructor que toma un valor y otra lista y devuleve una lista. En otras palabras, tiene dos campos. Uno es del tipo a y otro es del tipo [a].
ghci> Empty
Empty
ghci> 5 `Cons` Empty
Cons 5 Empty
ghci> 4 `Cons` (5 `Cons` Empty)
Cons 4 (Cons 5 Empty)
ghci> 3 `Cons` (4 `Cons` (5 `Cons` Empty))
Cons 3 (Cons 4 (Cons 5 Empty))
Si hubiésemos llamado a nuestro constructor de forma infija podrías ver mejor como es simplemente :. Empty es como [] y 4 `Cons` (5 `Cons` Empty) es como 4:(5:[]).
Podemos definir funciones que automáticamente sean infijas si las nombramos únicamente con caracteres especiales. Podemos hacer lo mismo con los constructores, ya que son simplemente funciones que devuelve un tipo de dato concreto. Mira esto:
infixr 5 :-:
data List a = Empty | a :-: (List a) deriving (Show, Read, Eq, Ord)
Antes de nada, vemos que hay una nueva construcción sintáctica, una declaración infija. Cuando definimos funciones como operadores, podemos usar esta cosntrucción para darles un determinado comportamiento (aunque no estamos obligados a hacerlo). De esta forma definimos el orden de precedencia de un operador y si asociativo por la izquierda o por la derecha. Por ejemplo, * es infixl 7 * y + es infixl 6 +. Esto siginifica que ambos son asociativos por la izquierda de forma que (4 * 3 * 2) es (4 * 3) * 2) pero * tiene un orden de precedencia mayor que +, por lo que 5 * 4 + 3 es equivalente a (5 * 4) + 3.
De qualquier modo, al final acabamos escribiendo a :-: (List a) en lugar de `` Cons a (List a)``. Ahora podemos escribir las listas así:
ghci> 3 :-: 4 :-: 5 :-: Empty
(:-:) 3 ((:-:) 4 ((:-:) 5 Empty))
ghci> let a = 3 :-: 4 :-: 5 :-: Empty
ghci> 100 :-: a
(:-:) 100 ((:-:) 3 ((:-:) 4 ((:-:) 5 Empty)))
Haskell seguirá mostrando el constructor como una función prefija cuando derivemos Show, por este motivo aparecen los paréntesis alrededor del constructor (recuerda que 4 + 3 es igual que (+) 4 3).
Vamos a crear una función que una dos de nuestras listas. Así es como está definida la función ++ para listas normales:
infixr 5 ++
(++) :: [a] -> [a] -> [a]
[] ++ ys = ys
(x:xs) ++ ys = x : (xs ++ ys)
Así que copiamos esta definición y la aplicamos a nuestras listas:
infixr 5 .++
(.++) :: List a -> List a -> List a
Empty .++ ys = ys
(x :-: xs) .++ ys = x :-: (xs .++ ys)
Y así es como funciona:
ghci> let a = 3 :-: 4 :-: 5 :-: Empty
ghci> let b = 6 :-: 7 :-: Empty
ghci> a .++ b
(:-:) 3 ((:-:) 4 ((:-:) 5 ((:-:) 6 ((:-:) 7 Empty))))
Fíjate que hemos utilizado un ajuste de patrón (x :-: xs). Esto función ya que el ajuste de patrones en realidad funciona ajustando constructores. Podemos ajustar un patrón :-: porque es un constructor de nuestro tipo de la misma forma que : es un constructor de las listas estándar. Lo mismo sucede para [].
Ya que el ajuste de patrones funciona (solo) con constructores de datos, podemos ajustar patrones como los constructores prefijos normales, constructores infijos o cosas como 8 o 'a', que al fin y al cabo son constructores de tipos numéricos y caracteres.
Piensa en la lista en Haskell [5]. Es lo mismo que 5:[]. A la izquierda del : hay un valore, y a la derecha hay una lista. En este caso, una lista vacía. ¿Qué pasaría con la lista [4,5]? Bueno, es lo mismo que 4:(5:[]). Si miramos el primer :, vemos que también tiene un elemento a su izquierda y una lista a su derecha (5:[]). Lo mismo sucede para la lista 3:(4:(5:6:[])), que también podría escribirse como 3:4:5:6:[] (ya que : es asociativo por la derecha) o [3,4,5,6].
Podemos decir que una lista es o bien una lista vacia o bien un elemento unido con un : a otra lista (que puede ser una lista vacía o no).
Podemos usar los tipo de datos algebraicos para implementar nuestra propia lista:
data List a = Empty | Cons a (List a) deriving (Show, Read, Eq, Ord)
Se lee de la misma forma que se leía nuestra definición de lista en un párrafo anterior. Es o bien una lista vacía o bien una combinación de un elemento y otra lista. Si estás confundido con esto, quizás te sea más fácil entenderlo con la sintaxis de registro:
data List a = Empty | Cons { listHead :: a, listTail :: List a} deriving (Show, Read, Eq, Ord)
Puede que también estes confundido con el constructor Cons. Cons es otra forma de decir :. En realidad, en las listas, : es un constructor que toma un valor y otra lista y devuleve una lista. En otras palabras, tiene dos campos. Uno es del tipo a y otro es del tipo [a].
ghci> Empty
Empty
ghci> 5 `Cons` Empty
Cons 5 Empty
ghci> 4 `Cons` (5 `Cons` Empty)
Cons 4 (Cons 5 Empty)
ghci> 3 `Cons` (4 `Cons` (5 `Cons` Empty))
Cons 3 (Cons 4 (Cons 5 Empty))
Si hubiésemos llamado a nuestro constructor de forma infija podrías ver mejor como es simplemente :. Empty es como [] y 4 `Cons` (5 `Cons` Empty) es como 4:(5:[]).
Podemos definir funciones que automáticamente sean infijas si las nombramos únicamente con caracteres especiales. Podemos hacer lo mismo con los constructores, ya que son simplemente funciones que devuelve un tipo de dato concreto. Mira esto:
infixr 5 :-:
data List a = Empty | a :-: (List a) deriving (Show, Read, Eq, Ord)
Antes de nada, vemos que hay una nueva construcción sintáctica, una declaración infija. Cuando definimos funciones como operadores, podemos usar esta cosntrucción para darles un determinado comportamiento (aunque no estamos obligados a hacerlo). De esta forma definimos el orden de precedencia de un operador y si asociativo por la izquierda o por la derecha. Por ejemplo, * es infixl 7 * y + es infixl 6 +. Esto siginifica que ambos son asociativos por la izquierda de forma que (4 * 3 * 2) es (4 * 3) * 2) pero * tiene un orden de precedencia mayor que +, por lo que 5 * 4 + 3 es equivalente a (5 * 4) + 3.
De qualquier modo, al final acabamos escribiendo a :-: (List a) en lugar de `` Cons a (List a)``. Ahora podemos escribir las listas así:
ghci> 3 :-: 4 :-: 5 :-: Empty
(:-:) 3 ((:-:) 4 ((:-:) 5 Empty))
ghci> let a = 3 :-: 4 :-: 5 :-: Empty
ghci> 100 :-: a
(:-:) 100 ((:-:) 3 ((:-:) 4 ((:-:) 5 Empty)))
Haskell seguirá mostrando el constructor como una función prefija cuando derivemos Show, por este motivo aparecen los paréntesis alrededor del constructor (recuerda que 4 + 3 es igual que (+) 4 3).
Vamos a crear una función que una dos de nuestras listas. Así es como está definida la función ++ para listas normales:
infixr 5 ++
(++) :: [a] -> [a] -> [a]
[] ++ ys = ys
(x:xs) ++ ys = x : (xs ++ ys)
Así que copiamos esta definición y la aplicamos a nuestras listas:
infixr 5 .++
(.++) :: List a -> List a -> List a
Empty .++ ys = ys
(x :-: xs) .++ ys = x :-: (xs .++ ys)
Y así es como funciona:
ghci> let a = 3 :-: 4 :-: 5 :-: Empty
ghci> let b = 6 :-: 7 :-: Empty
ghci> a .++ b
(:-:) 3 ((:-:) 4 ((:-:) 5 ((:-:) 6 ((:-:) 7 Empty))))
Fíjate que hemos utilizado un ajuste de patrón (x :-: xs). Esto función ya que el ajuste de patrones en realidad funciona ajustando constructores. Podemos ajustar un patrón :-: porque es un constructor de nuestro tipo de la misma forma que : es un constructor de las listas estándar. Lo mismo sucede para [].
Ya que el ajuste de patrones funciona (solo) con constructores de datos, podemos ajustar patrones como los constructores prefijos normales, constructores infijos o cosas como 8 o 'a', que al fin y al cabo son constructores de tipos numéricos y caracteres.
Tutorial de Ceylon
Si quieres aprender Ceylon rápidamente este tutorial es para vos : http://lmauzaize.developpez.com/tutoriels/ceylon/typage/
jueves, 16 de octubre de 2014
Standard ML
Estoy haciendo el curso de corsera sobre lenguajes de programación y en este curso se estudia Standard ML y madre mía ,que lenguaje!!! Y obvio despertó mi curiosidad, veamos que nos dice la wikipedia sobre SML:
"El lenguaje de programación Standard ML o SML es un lenguaje descendiente del lenguaje ML que nació como el Meta Lenguaje del sistema LCF. A diferencia de muchos otros lenguajes de programación, SML tiene una especificación formal, como semántica operacional publicada en el libro The Definition of Standard ML."
Yo ya hable de SML en otro post pero mi inconstancia, no dejo que profundice. Seguramente estas pensando que me puede aportar este lenguaje? Que lo hace especial?
Como primer punto es un lenguaje funcional y es de tipado estático, con genéricos. A la vez el compilador infiere los tipos por lo que tiene el sistema de tipos más simple y mejor diseñado que he usado, y si no mira:
- val i = 2
val i = 2 : int
- val miLista = [1,1,3,4,5]
val miLista = [1,1,3,4,5] : int list
- val otraLista = [miLista, [1,2,8]]
val otraLista = [[1,1,3,4,5],[1,2,8]] : int list list
- val unString="unString"
val unString = "unString" : string
Si ven otraLista es de tipo list y es genérica. Y este genérico es de tipo lista de enteros, en java sería así:
List<List<Integer>>
Al ser un lenguaje funcional las funciones son lo más importante, y se definen de la siguiente manera:
- fun sumar (a:int, b:int):int = a + b
val sumar = fn : int * int -> int
- sumar (4, 5)
val it = 9 : int
"El lenguaje de programación Standard ML o SML es un lenguaje descendiente del lenguaje ML que nació como el Meta Lenguaje del sistema LCF. A diferencia de muchos otros lenguajes de programación, SML tiene una especificación formal, como semántica operacional publicada en el libro The Definition of Standard ML."
Yo ya hable de SML en otro post pero mi inconstancia, no dejo que profundice. Seguramente estas pensando que me puede aportar este lenguaje? Que lo hace especial?
Como primer punto es un lenguaje funcional y es de tipado estático, con genéricos. A la vez el compilador infiere los tipos por lo que tiene el sistema de tipos más simple y mejor diseñado que he usado, y si no mira:
- val i = 2
val i = 2 : int
- val miLista = [1,1,3,4,5]
val miLista = [1,1,3,4,5] : int list
- val otraLista = [miLista, [1,2,8]]
val otraLista = [[1,1,3,4,5],[1,2,8]] : int list list
- val unString="unString"
val unString = "unString" : string
Si ven otraLista es de tipo list y es genérica. Y este genérico es de tipo lista de enteros, en java sería así:
List<List<Integer>>
Al ser un lenguaje funcional las funciones son lo más importante, y se definen de la siguiente manera:
- fun sumar (a:int, b:int):int = a + b
val sumar = fn : int * int -> int
- sumar (4, 5)
val it = 9 : int
Como ven la función sumar es de tipo int * int -> int , lo que significa que tiene dos parámetros enteros y devuelve un entero.
Otro tipo interesante son las tuplas, son colecciones de elementos de un mismo tipo que se pueden acceder por un indice, similar a los arreglos:
- fun sumarTupla(tupla: int * int) : int = #1 tupla + #2 tupla
val sumarTupla = fn : int * int -> int
- sumarTupla((1,2))
val it = 3 : int
SML es un lenguaje que tiene un sistema de tipos muy simple, voy a seguir postiando cosas interesantes sobre el lenguaje.
sábado, 11 de octubre de 2014
Que lenguaje deben enseñar en la facultad y cual no? y porque?
Es bueno que la facultad enseñe los lenguajes más utilizados? Debe enseñar conceptos y no lenguajes?
En mi opinión la facultad no debería preocuparse si el lenguaje se utiliza o no en el mercado, es más mejor si enseña uno que no usa nadie, así el alumno tiene que aprender otros y por su cuenta.
Por favor comenten que piensan!!
Ruby vs. The World
Quiero compartir con ustedes este muy interesante video y presentación que compara o habla de diferentes lenguajes modernos.
Dejo link: http://matt.aimonetti.net/posts/2012/11/02/rubyconf-2012-ruby-vs-the-world/
Dejo link: http://matt.aimonetti.net/posts/2012/11/02/rubyconf-2012-ruby-vs-the-world/
miércoles, 8 de octubre de 2014
The Linux Foundation Certification Program
Todo comenzó con un curso en EDX y ahora linux foundation no solo nos regala un curso, sino que también nos permite certificarnos como sysadmin o engineer.
Dejo el link: http://training.linuxfoundation.org/certification/
Multiple Dispatch
Quiero recomendarles el siguiente articulo "Multiple Dispatch" si estan interesados en que es el double Dispach y por que es interesado.
sábado, 4 de octubre de 2014
ExpressionBuilder
Cuando realizamos Unit test necesitamos crear componentes o objetos para testear, no se puede
mockear todo. Una muy buena idea es construir nuestros objetos con builders. A la vez podemos reutilizar estos builder en diferentes tests.
mockear todo. Una muy buena idea es construir nuestros objetos con builders. A la vez podemos reutilizar estos builder en diferentes tests.
Una idea muy buena son los ExpressionBuilders, que son builders que simulan un DSL para construir objetos. Es muy Elegante:
customer.newOrder()
.with(6, "TAL")
.with(5, "HPK").skippable()
.with(3, "LGV")
.priorityRush();
Esto se logra haciendo que el builder contenga la instancia que debe construir y cada vez que se llama a with o otro método que setea la instancia, devolvemos this, para poder encadenar los llamados.
Queda de esta forma:
public class OrderBuilder {
private Order subject = new Order();
private OrderLine currentLine;
public OrderBuilder with(int quantity, String productCode) {
currentLine = new OrderLine(quantity, Product.find(productCode));
subject.addLine(currentLine);
return this;
}
public OrderBuilder skippable() {
currentLine.setSkippable(true);
return this;
}
public OrderBuilder priorityRush() {
subject.setRush(true);
return this;
}
public Order getSubject() {
return subject;
}
}
Por supuesto que esta técnica no solo se puede utilizar en unit test...
Suscribirse a:
Entradas (Atom)