Automágica: durante 2017 estoy trabajando bastante en Automágica, mi software para editar libros: Más información - Posts relacionados


Primera vez con Ruby

El viernes por la tarde salí del trabajo y me fuí a escuchar la charla de César Ballardini, El modelo de objetos de Ruby, reflexiones sobre la reflexión. La daba en el marco del evento acts_as_rubylit, el cual se llevó a cabo en la Facultad de Ingeniería y Ciencias Hídricas, Universidad Nacional del Litoral de la ciudad de Santa Fe.

Nunca antes vi nada de Ruby. Bueno, casi, pero la última vez no pasé del Hola Mundo!juanjo_ruby_800

César empezó su charla explicando la Paradoja de Blub, de Paul Graham. Blub es un lenguaje de programación hipotético. No es el lenguaje de programación más poderoso, pero tampoco es Cobol o lenguaje de máquina. Un programador Blub está parado más o menos en el medio de la ladera de una montaña; hacia abajo están los lenguajes menos poderosos que Blub, él se da cuenta de esto, por supuesto, a todos esos lenguajes le faltan distintas características que nuestro programador usa en Blub para resolver sus problemas. En cambio, cuando mira para arriba (y ve lenguajes más poderosos que Blub), en realidad no se da cuenta que está mirando hacia arriba, simplemente piensa que está mirando a unos locos, hippies de pelos parados haciendo cosas raras. Cuando los programadores que están más arriba en la montaña miran hacia Blub se pregunta, ¿cómo puede alguien estar usando Blub? Ni siquiera tiene la funcionalidad X tan útil para resolver Y!

Por inducción se concluye que solo el programador que esté en la punta de la montaña, es decir el que conoce el lenguaje más poderoso, es capaz de distinguir las distintas posibilidades que se tienen con diferentes lenguajes. El programador Blub no puede verlo, por lo que solo sabe pensar en Blub, no se a enfrentado a problemas que le permitan pensar diferente.

La moraleja de la historia es que uno debería aprender lenguajes que lo obliguen a cambiar su forma de pensar y de resolver problemas (Alan J. Perlis).

Con esto terminó la primera parte de la charla, luego César hizo una explicación de pizarrón sobre qué es la Programación Orientada a Objetos ( y escribió con su fibrón: un objeto tiene Identidad, encapsula Estado y define Comportamiento). Según César, es un error que en la enseñanza de la POO se empiece por las Clases. ¿En qué parte de "Programación Orientada a Objetos" dice "Clase"? Las clases son solo una forma de crear objetos, pero hay muchas otras. Por ejemplo, existen muchos lenguajes OO basados en prototipos, como JavaScript.

Después de haber shockeado a la audiencia desarrollando estas dos ideas en un tono casi de declaración de principios, estábamos listos para ver cómo el Modelo de Objetos de Ruby podía cambiar nuestra forma de pensar.

Lo que sigue no son los ejemplos exactos que desrrolló César con su notebook, solo los que recuerdo. Mezclo los recuerdos de su sesión interactiva de Ruby con mi propio camino de aprendizaje, que arranca ni siquiera teniendo el intérprete instalado :)

Para empezar los ejemplos, tipeó en la terminal

irb

. Hice lo mismo, pero no estaba instalado, por lo que instalé ese paquete y presté atención a sus dependencias:

juanjo@fenix:~$ irb

El programa «irb» no está instalado actualmente. Puede instalarlo escribiendo:

sudo apt-get install irb

bash: irb: orden no encontrada

juanjo@fenix:~$ sudo apt-get install irb

[sudo] password for juanjo:

Leyendo lista de paquetes... Hecho

Creando árbol de dependencias

Leyendo la información de estado... Hecho

Se instalarán los siguientes paquetes extras:

irb1.8 libreadline-ruby1.8 ruby1.8

Paquetes sugeridos:

ruby1.8-examples rdoc1.8 ri1.8

Se instalarán los siguientes paquetes NUEVOS:

irb irb1.8 libreadline-ruby1.8 ruby1.8

0 actualizados, 4 se instalarán, 0 para eliminar y 0 no actualizados.

Necesito descargar 119kB de archivos.

Se utilizarán 664kB de espacio de disco adicional después de esta operación.

¿Desea continuar [S/n]?

Des:1 http://ar.archive.ubuntu.com jaunty-updates/main ruby1.8 1.8.7.72-3ubuntu0.1 [24,0kB]

Des:2 http://ar.archive.ubuntu.com jaunty-updates/universe libreadline-ruby1.8 1.8.7.72-3ubuntu0.1 [10,4kB]

Des:3 http://ar.archive.ubuntu.com jaunty-updates/universe irb1.8 1.8.7.72-3ubuntu0.1 [79,1kB]

Des:4 http://ar.archive.ubuntu.com jaunty/universe irb 4.2 [5138B]

Descargados 119kB en 2s (58,0kB/s)

Seleccionando el paquete ruby1.8 previamente no seleccionado.

(Leyendo la base de datos ...

248649 ficheros y directorios instalados actualmente.)

Desempaquetando ruby1.8 (de .../ruby1.8_1.8.7.72-3ubuntu0.1_i386.deb) ...

Seleccionando el paquete libreadline-ruby1.8 previamente no seleccionado.

Desempaquetando libreadline-ruby1.8 (de .../libreadline-ruby1.8_1.8.7.72-3ubuntu0.1_i386.deb) ...

Seleccionando el paquete irb1.8 previamente no seleccionado.

Desempaquetando irb1.8 (de .../irb1.8_1.8.7.72-3ubuntu0.1_all.deb) ...

Seleccionando el paquete irb previamente no seleccionado.

Desempaquetando irb (de .../apt/archives/irb_4.2_all.deb) ...

Procesando disparadores para man-db ...

Procesando disparadores para menu ...

Configurando ruby1.8 (1.8.7.72-3ubuntu0.1) ...

Configurando libreadline-ruby1.8 (1.8.7.72-3ubuntu0.1) ...

Configurando irb1.8 (1.8.7.72-3ubuntu0.1) ...

Configurando irb (4.2) ...

Procesando disparadores para menu ...NAME

   irb1.8 - interactive ruby

SYNOPSIS

   irb [options]

DESCRIPTION

irb stands for ‘interactive ruby’. irb is a tool to execute interactively ruby expressions read from stdin. Use of irb is easy if

   you know ruby.  Executing irb, prompts are displayed as follows. Then, enter expression of ruby. A input is executed  when  it  is

   syntacticaly completed</strong>.

Ahora si puedo empezar!

Objetos y mensajes

Un lenguaje OO consta de objetos y mensajes entre objetos. Algunas veces los mensajes están un poco camuflados, pero siempre están ahí:

irb(main):001:0> 1 + 2

=> 3

irb(main):002:0> 1.+ 2

=> 3

irb(main):003:0> 1.+(2) # para los lisperos que extrañan los paréntesis

=> 3

Identidad

Enviando el mensaje

object_id

, podemos preguntarle su identidad a un objeto:

irb(main):001:0> 1.object_id

=> 3

irb(main):002:0> "hola".object_id

=> -605926728

Clases

Enviando el mensaje

class

a un objeto, podemos preguntarle quién es su clase:

irb(main):005:0> 1.class

=> Fixnum

irb(main):006:0> 1.class.class

=> Class

irb(main):007:0> 1.class.class.class

=> Class

Podemos ver que la clase Fixnum es una instancia de la clase Class; y la clase Class también es instancia de la clase Class.

Enviando el mensaje

superclass

a una clase, podemos saber cual es su superclase, es decir, qué clase extiende.

irb(main):010:0> 1.class.superclass

=> Integer

irb(main):011:0> 1.class.superclass.superclass

=> Numeric

irb(main):012:0> 1.class.superclass.superclass.superclass

=> Object

Luego, la clase de Object es obviamente Class, pero... ¿cuál es su superclase?

irb(main):019:0> 1.class.superclass.superclass.superclass

=> Object

irb(main):020:0> 1.class.superclass.superclass.superclass.superclass

=> nil

Creo recordar que en SmallTalk también era así. Parece un chiste de los diseñadores :) nil ni siquiera es una clase:

irb(main):021:0> 1.class.superclass.superclass.superclass.superclass.superclass

NoMethodError: undefined method `superclass' for nil:NilClass

    from (irb):21

    from :0

irb(main):022:0> 1.class.superclass.superclass.superclass.superclass.class

=> NilClass

irb(main):023:0> 1.class.superclass.superclass.superclass.superclass.class.superclass

=> Object

irb(main):024:0> 1.class.superclass.superclass.superclass.superclass.class.class

=> Class

y la jerarquía de clases se cierra. Es para leer tranquilo y pensarlo.

El resto de la charla abarcó varias cosas más, pero creo que sería demasiado para desarrollarlo en un post y lo que mostré ya es suficiente para abrirle el apetito a los que estén buscando algún lenguaje para aprender y les produzca un cambio en su forma de pensar :). Si César postea sus ejemplos, los voy a estar referenciando desde aquí o voy a intentar hacer uno o dos posts más.

Gracias al Grupo de Usuarios de Ruby del Litoral por organizar el evento!


Entorno de desarrollo SWI-Prolog

Uso SWI-Prolog, una de las implementaciones más potentes y populares del lenguaje. Para Windows, está disponible un entorno de desarrollo compuesto básicamente por:

    <li>Un panel dónde escribir código con resaltado de sintáxis.</li>
    
    <li>Botones para hacer cosas como consultar el archivo que estamos editando (esto es compilarlo y cargarlo en memoria para poder hacer consultas sobre él).</li>
    
    <li>Un panel dónde realizar consultas.</li>
    

    En los sistemas operativos basados en Linux (como Ubuntu) no existe un entorno similar. Los programadores full-time Prolog deben tener su forma de solucionarlo. Yo encontré la mía. Puede no ser la mejor, pero es más cómoda que tipear por un lado, tener el intérprete abierto por otro e ir consultando luego de cada modificación.

    De hecho, la misma implementación trae algunas primitivas útiles que se pueden usar desde el lenguaje. Por ejemplo:

    ?- consult('cats.pdb').
    
    % cats.pdb compiled 0.01 sec, 1,664 bytes
    
    true.

    compilará el archivo cats.pdb y los hechos y reglas definidos en él estarán disponibles para nuestras consultas. Si modificamos el archivo fuente, luego debemos hacer:

    ?- reconsult('cats.pdb').
    
    % cats.pdb compiled 0.00 sec, 0 bytes
    
    true.

    para que las modificaciones tengan efecto. Encontré otro predicamo muy útil:

    ?- edit('cats.pdb').
    
    % Waiting for editor ...
    
    % Running make to reload modified files
    
    % /home/juanjo/prolog/cats.pdb compiled 0.00 sec, 124 bytes
    
    % Scanning references for 1 possibly undefined predicates
    
    true.

    Abrirá el editor por defecto configurado en la computadora, nos permitirá editar el archivo y cuando lo guardemos retorna true al intérprete. Ahora lo que antes hacíamos a mano, podemos hacerlo desde el intérprete. Un avance, pero se pone mejor: podemos usar estos predicados Prolog para escribir una regla que haga todo por nosotros. Yo uso:

    myedit(File) :-
    
    edit(File), reconsult(File).
    
    myedit(File) :-
    
    edit(file(File)), reconsult(File).

    ¿Cómo funciona? Primero notemos que son dos reglas. La primera recibe un nombre de archivo e intenta editarlo, si el archivo existe se abre el editor, editamos, cuando lo guardamos edit(File) evalúa true y se pasa al siguiente hecho que reconsulta el archivo y listo.

    Si el archivo no existe, la primer regla no termina y se pasa a la segunda. file(File) se encarga de crearlo y edit podrá editarlo, trabajamos y todo termina como en el caso anterior.

    Podemos escribir este código en el archivo .plrc de nuestra home para que sea cargado al iniciar el intérprete. Finalmente si utilizamos la extensión .pdb, vim se encarga de cargar el resaltado correspondiente a la sintácis de Prolog.


    De paseo por Capital

    Este año tuve que viajar más veces a Capital Federal de las que había viajado en toda mi vida (creo), pero casi nunca tuve tiempo de pasear. Este finde viajamos por que a Ceci le entregaba un premio la Academina Nacional de Ingeniería (mejor egresada de la Facultad Regional Santa Fe - UTN - 2008). Así que estuvimos de paseo, principalmente por la zona del obelisco, que es dónde estaba el hotel:

    [gallery link="file" orderby="title"]

    update: Otras fotos, pero solo del premio.


    Prolog, un lenguaje realmente diferente

    Hace unos años escuché una charla de Pupeno titulada "Lips, un lenguaje diferente". Fue una charla muy interesante y realmente logró sorprender a muchos de la audiencia con distintas características de Lisp.

    Sin embargo, creo que Lisp no es tan diferente a otros lenguajes. Ok, se basa en un paradigma (el funcional) distinto al que se basa la mayoría (lideran los rankings el paradigma procedural y el paradigma orientado a objetos). Pero aún así, no está tan lejos. De hecho, muchos lenguajes de programación tienden a Lisp.

    Prolog es el lenguaje más conocido, y otros prácticamente no se mencionan, del paradigma lógico. No es un paradigma imperativo (como los anteriormente mencionados) en el cual debemos decirle a la computadora cómo resolver un problema (poné en esta variable este valor multiplicado por dos, iterá hasta que n sea igual a 10, etc...) sino que es un paradigma declarativo: simplemente se plantean afirmaciones sobre los objetos y sus relaciones.

    Un programa Prolog está compuesto de dos partes: una base de conocimiento + consultas contra esta. Ambas partes se escriben utilizando la misma sintaxis. Una vez que se tiene escrita la base de conocimientos, esta es compilada o interpretada y ya está lista para qué se realicen consultas contra ella.

    Los siguientes son 3 ejemplos básicos de programas Prolog.

    Base de conocimiento familiar

    Vamos a utilizar Prolog para armar una base de conocimiento con relaciones familiares. Empezamos con hechos; se expresan las relaciones padre y madre:

    padre(raul, juanjo).
    
    padre(raul, marisu).
    
    madre(susana, juanjo).
    
    madre(susana, marisu).
    
    madre(nieve, raul).

    Y una regla, que se lee: X es abuela de Y si X es madre de Z y Z es madre de Y ó X es padre de Y.

    abuela(X, Y) :- madre(X, Z), madre(Z, Y).
    
    abuela(X, Y) :- madre(X, Z), padre(Z, Y).

    Con esta base definida, podemos compilarla y hacerle consultas. ¿De quiénes es padre raul?

    ?- padre(raul, X).
    
    X = juanjo ;
    
    X = marisu.

    ¿Quién es abuela de quién?

    ?- abuela(X,Y).
    
    X = nieve,
    
    Y = juanjo ;
    
    X = nieve,
    
    Y = marisu.

    nota: por lo general, la interfaz de Prolog nos da la primer respuesta que encuentra y con ; le pedimos la siguiente.

    Factorial

    Definir un predicado que calcule el factorial de un número es bastante directo en Prolog. Si tenés que explicar la función factorial a alguien le decís: el factorial de 0 es 1. El factorial de N es N por el factorial de N - 1. Escribimos eso en Prolog:

    factorial(0, 1) :- !.
    
    factorial(N, F) :- N1 is N - 1, factorial(N1, F1), F is N*F1.

    Con este programa compilado, podemos hacer las siguientes consultas:

    ?- factorial(0, N).
    
    N = 1.
    
    ?- factorial(6, N).
    
    N = 720.
    
    ?- factorial(6, 555).
    
    false.

    Podemos pedir el factorial de un número e indicar la variable dónde obtener la respuesta o consultar con un predicado sin variables (ground) y obtener como respuesta el valor de verdad de la misma.

    Concatenar listas

    Un tipo de dato poderoso que incorpora Prolog son las listas. Podemos definir un predicado que concatene listas. Lo vamos a llamar concatenar y tendrá 3 argumentos: las dos listas a concatenar y el resultado de la operación. Luego podremos usar el predicado de esta forma:

    ?- concatenar([1,2], [4,5,6], L).
    
    L = [1, 2, 4, 5, 6].
    
    
    
    ?- concatenar(X, Y, [4,5,6]).
    
    X = [],
    
    Y = [4, 5, 6] ;
    
    X = [4],
    
    Y = [5, 6] ;
    
    X = [4, 5],
    
    Y = [6] ;
    
    X = [4, 5, 6],
    
    Y = [] ;
    
    false.

    Definir este predicado en Prolog es muy sencillo:

    concatenar([],L,L).
    
    concatenar([X|L1],L2,[X|L3]):-concatenar(L1,L2,L3).

    Tiene dos partes y se lee así:

    Concatenar la lista vacía con L, da como resultado L.

    Concatenar una lista cuya cabeza es X y cola L1 con L2, da como resultado la lista de cabeza X y cola L3 SI el resultado de concatenar L1 con L2 es L3.

    Fin del tour

    Este fue un tour acelerado por Prolog, tuvo como objetivo mostrárselo a quienes no lo conocen, dejarles el gusto en la boca y ganas de mas. ¿Lo logré? ¿No conocías Prolog? ¿Qué pensás ahora?

    Tutoriales y otros enlaces

    Notas


    Semana de la seguridad

    semanaSegEn el año 1988, la Association for Computing Machinery (ACM) declaró al 30 de Noviembre como el “Día Internacional de la Seguridad Informática”, con el objetivo de concientizar respecto de las amenazas que atentan contra la seguridad de la información.

    Esta semana es la Semana de la Seguridad. En Argentina la organiza la Jefatura de Gabinete de ministros. En Santa Fe AsegurarTe está organizando algunas charlas y me invitaron a dar mi charla sobre Taint Mode en Python el día miércoles 25 a las 12:30 en la Dirección de Informatización y Planificación Tecnológica de Rectorado de la UNL. Desconozco qué porcentaje de los asistentes conocen Python, por lo que voy a intentar centrarme más en los conceptos que en la implementación concreta de esta técnica; así como definir bien el problema, plantear sus implicacias y discutir soluciones.

    update: un par de fotos!

    100_5410

    100_5412


    Algunas fotos del 34° acto de colación de grado

    Anoche fue el 34° acto de colación de grado en la UTN FRSF. Luego fue la fiesta anual de la facultad, a la que nos quedamos con varios comapañeros.

    100_5363_s

    Pronto más fotos :)

    update: un par de fotos de las tomadas por Flor Citta.

    SANY1452

    Florcitta y Meli

    Mariano


    Conjuntos en Python

    Cuando estaba preparando mi charla introductoria a Python, le pasé mis slides a un amigo para que me diga su opinión y una de las cosas que me dijo fue

    Nunca senti que set sea algo nativo de python, le daria mas importancia a los diccionarios, aunque tal vez tu publico este mas interesado en sets, no lo se.

    Me sorprendió el comentario. Para mi, set es un tipo de dato muy útil y poderoso. En este post voy a intentar hacer una apología de set, el tipo de dato que incorpora Python para representar la noción matemática de conjunto.

    Presentación

    Un objeto set es una colección sin orden de objetos hasheables. Puede contener objetos de todos los tipos inmutables de Python, pero no los contenedores mutables como listas. También puede contener objetos de clases definidas por el usuario (Los objetos instancias de clases definidas por el usuario son por defecto hasheables.).

    Los conjuntos se pueden crear, por ejemplo, a partir de una lista. Podemos quitar elementos (al azar o uno en concreto) o agregarlos:

    >>> heladera = ['huevo', 'huevo', 'queso', 'leche', 'pera', 'pera', 'pera']
    
    >>> alimentos = set(heladera)
    
    >>> alimentos
    
    set(['queso', 'leche', 'huevo', 'pera'])
    
    >>> alimentos.pop()
    
    'queso'
    
    >>> alimentos.remove('leche')
    
    >>> alimentos
    
    set(['huevo', 'pera'])
    
    >>> alimentos.add('empanada')
    
    >>> alimentos
    
    set(['empanada', 'huevo', 'pera'])

    Prueba de pertenencia

    Otra función muy común y útil es probar la pertenencia de objetos al conjunto:

    >>> 'empanada' in alimentos
    
    True
    
    >>> 'leche' in alimentos
    
    False
    
    >>> 'leche' not in alimentos
    
    True
    
    

    Iterar sobre conjuntos

    Podemos interar sobre conjuntos de la misma forma que lo hacemos sobre listas:

    >>> for a in alimentos:
    
    ...     "Debo comer " + a
    
    ...
    
    'Debo comer empanada'
    
    'Debo comer huevo'
    
    'Debo comer pera'
    
    

    Operaciones sobre conjuntos

    Los conjuntos en Python soportan las operaciones típicas de conjuntos: restas, intersección, unión y diferencia simétrica (los elementos que están en uno de los conjuntos, pero no en ambos). Repasar operaciones con conjuntos.

    >>> frutas = set(['banana', 'naranja', 'pera'])
    
    >>> frutas - alimentos
    
    set(['banana', 'naranja'])
    
    >>> alimentos - frutas
    
    set(['huevo', 'empanada'])
    
    >>> frutas & alimentos
    
    set(['pera'])
    
    >>> frutas | alimentos
    
    set(['huevo', 'empanada', 'pera', 'banana', 'naranja'])
    
    >>> frutas ^ alimentos
    
    set(['huevo', 'empanada', 'banana', 'naranja'])

    También podemos preguntar sin un conjunto es subconjunto de otro. En los ejemplos se utiliza set(), el conjunto vacío:

    >>> alimentos < set()
    
    False
    
    >>> set() < alimentos
    
    True
    
    >>> set() > alimentos
    
    False
    
    >>> alimentos <= alimentos
    
    True
    
    

    El problema de las dos comisiones

    Este problema está basado en un caso real y lo escuché en la charla Escribí menos código, pensá como un (buen) matemático de Gustavo Carmona (FCEYN - UBA) bio y Matías A Graña (FCEyN - UBA) bio.

    Se tienen dos archivos de textos con una lista de e-mails en cada uno. Cada archivo tiene los mails de los funcionarios de una comisión; los archivos no están bien depurados, por lo que pueden contener direcciones repetidas; hay funcionarios trabajando en las dos comisiones. Luego de una reunión en la que trabajaron ambas comisiones, se generó un material que se necesita enviar a todos los participantes. ¿Cómo obtener la lista de destinatarios?

    archivo1
    
    dir1@mail.com
    
    dir2@mail.com
    
    dir3@mail.com
    
    dir1@mail.com
    archivo2
    
    dir21@mail.com
    
    dir23@mail.com
    
    dir3@mail.com
    
    dir1@mail.com

    Queremos una tercera lista que tenga la primera más la segunda, pero que no estén repetidos.

    El enfoque tradicional que utilizaría un programador para resolver este problema mediante bucles es:

    def unionlarga(l1, l2):
    
        l3 = []
    
        for x in l1:
    
            if not x in l3:
    
                l3.append(x)
    
        for x in l2:
    
            if not x in l3:
    
                l3.append(x)
    
        return l3

    Supongamos que ya tenemos los archivos leídos y almacenamos el contenidos en listas:

    >>> unionlarga(archivo1, archivo2)
    
    ['dir1@mail.com', 'dir2@mail.com', 'dir3@mail.com',
    
    'dir21@mail.com', 'dir23@mail.com']

    La solución es genérica para cualquier lenguaje. Sin embargo, puede lograr una mejor solución utilizando sets en Python:

    >>> list(set(archivo1) | set(archivo2))
    
    ['dir21@mail.com', 'dir3@mail.com', 'dir2@mail.com',
    
    'dir1@mail.com', 'dir23@mail.com']

    Convertimos ambas listas a conjuntos (con lo que se eliminan los repetidos dentro de las listas), realizamos la unión de ambos conjuntos (con lo que se eliminan los repetidos entre listas y finalmente se convierte el resultado en una nueva lista.

    Más sobre conjuntos en la referencia del lenguaje.