Joaquin Tita: Review of Metaphor, myth and mimicry: the bases of software engineering

In the paper "Metaphor, myth, and mimicry: the bases of software engineering", Antony Bryant  analyses the problematic around the term "software engineering", exposing and discussing multiple point of views from different recognised authors over the last years concerning what brings with (as unwanted baggage) the use of the status "engineering" in software.

Bryant opens his paper saying that in the 80s the term wasn't problematic at all and used to be a "good thing" but with the pass of time, the concept was transformed into more activities than just ordinary programming. The idea that software had to be "engineered" gave an image of rigour, care and assurance. However, soon began to be often misunderstood. In the late 90s, there was a consensus over the term within the academic and research community. Later discussions threads on the electronic list from the Conference of Professors and Heads of Computing produced and accepted what involves research, the study of computing, informatics, software engineering and other related terminology. Anyhow, the ones that were senior academic understood it but not the ones that were outside that domain such as practitioners, wider engineering communities, potential students and so on. In this point, is where Bryant sets the dilemma that software developers wants to imitate engineers and demand the status of an engineering discipline but commercial demands and consumer desires do not support this. Likewise, he suggests that maybe the term by itself adds extra complexity or confusion. This is where he wants to focus much more in depth in the rest of his work.  

Looking much in depth the second section, the author tries to expose the distinct opinions of different authors about what software engineering is and fundamental key points to take into account. His goal is to reflect the ambiguity or unclearness of some ideas that still predominates over time caused by an emerging discipline that still needs to establish itself. Also, he strongly points out that terminology highly influence knowledge and the practice. [o] I think the terminology will always be an obstacle when it comes to the definition of software engineering. Consequently, the practice and domain will always be affected. 

Moving on to the third section, Brooks's classic paper "No Silver Bullet" comes into consideration to depict the dilemma of software engineering. Moreover, in his work he expressed his worry about the use of construction metaphors in software engineering (also referring at this as the replacement of a metaphor by another) that derive in a powerful impact on people's practices and cognition. From this, maybe the term "software engineering" itself its constraining rather helping in software development. At the end, the author of this paper poses the idea of rejecting metaphors altogether or at least admit the side effects of them. In my opinion, trying to eliminate all the existent metaphors can have serious drawbacks. People are used to them, they feel comfortable with them and literature from many years ago use it. Additionally, there will be cases where people will refuse in changing their way of thinking. Thus, the only suitable choice is admitting the drawbacks and live with them. Maybe, as an extreme idea, we could create new metaphors but again we will come again to the starting point of the discussion. 

In order to analyse and dismantle the engineering metaphor for software development, the author presents two examples. The first one, IT, illustrates how terminology generates a barrier for understanding what the term means. For instance, causing people erroneously apply for a job in IT or not applying to it. Frankly, I still have doubts about the definition of the term and I have always seen as clear example of how a word can blur a job or area.
The second one, requirements, is much more critical to software development practices. There is a general idea that requirements phase is seen as the most important and most difficult phase. Furthermore, the term "requirements engineering", is associated to activities that lead to the creation of the products of these phase. The terminology surrounding requirements for computer-based systems is replete with references to the engineering metaphor. Similarly, the idea that a good requirement specification should be clear, concise, concrete, and so on. Moreover, the assumption is that the requirement process must be systematic with some elements of formality and management. Bryant states that although the engineering metaphor provides a useful basis it's partially correct, arguing that it might obscure key features of the process.

I partially agree with Bryant in saying that metaphors hide or blur key aspects, but the reality also indicates that they also form a basic human mechanism to transform or interpret complex ideas or concepts in a more humane way. Personally, I don't think that metaphors obscure essential aspects if they are handled correctly.  

Also, to depict how communication can have a big impact in the interpretation of the ideas, the author explains the conduit metaphor. The underlying concept of the conduit metaphor is that the information is transferred from one point or person to another. Good communication flows without blockages and good reception involves extraction and unwrapping it. 

From my point of view, failure in the communication within all the parts involved is due a series of factors. As Davis stated paraphrasing Demarco, anyone involved in requirements should have strong human skills, communication skills, feeling skills and listening skills. Moreover, communication will fail without applying the proper effort. That is why I think that should be encouraged from the very first time.

Finally, the paper ends suggesting that the engineering metaphor moved us forward in the activity of developing a discipline for software development. I could not agree more with his statement. Personally, I believe that even though we are not seeing clearly where are we going or from where are we coming eventually we will find the appropriate foundation. Logically more discussions and new points of view will arise making us reformulate theory and concepts.

Gonzalo Martinez: Rockeandola con Python Parte 2

Siguiendo los pasos de magmax [0]

Diccionarios que se comportan como objetos

En este ejemplo vamos a crear una clase que hereda todas las funcionalidades de un diccionario solo vamos a modificar las funciones de obtener el atributo y de asignarle un atributo para interfacearlos con los del diccionario.

Esta es la definición de la clase:

class DictObject(dict):
    def __getattr__(self, key):
        return self[key]

    def __setattr__(self, key, value):
        self[key] = value

Esta es la implementación de la misma.

>>> d = DictObject()
>>> d['uno'] = 'one'
>>> d.uno
'one'
>>> d['uno']
'one'

Hacer esto nos genera un inconveniente por que las clases para los atributos tienen ciertas restricciones como que no se pueden comenzar con números, contener espacios ni otros signos de puntuación por consiguiente va a haber valores que no vamos a poder usar.

Closures == Clausura <> Torneo Clausura

Siguiendo una recomendación que se dá en los comentarios del Post de JuanjoConti[1] voy a tratar de contarles antes de empezar con los decoradores que es un Closure.

En Informática, una clausura es una función que es evaluada en un entorno conteniendo una o más variables dependientes de otro entorno. Cuando es llamada, la función puede acceder a estas variables. El uso explícito de clausuras se asocia con programación funcional y con lenguajes como el ML y el Lisp. Construcciones como los objetos en otros lenguajes pueden ser también modelados con clausuras. [2]
Un ejemplo de clausura es puede observar en la implementación de los decoradores a continuación.

Decoradores

Un decorador es una función 'a' que recibe como argumento otra función 'b' y devuelve una función 'c' que es la función 'b' decorada con 'a'.

Imaginemos que necesitamos loggear el acceso y salida de una función por pantalla.

>>> def avisar(f):
...     def inner(*args, **kwargs):  ## Esta es una clausura
...             print 'Se ejecuta la funcion %s' % f.__name__
...             f(*args, **kwargs)
...             print 'Se termino de ejecutar %s' % f.__name__
...     return inner
...
>>> def SumaLoca(a,b):
...     print a + b
...
>>> SumaLoca(10,5)
15
>>> avisarSumaLoca = avisar(SumaLoca)
>>> avisarSumaLoca(10,6)
Se ejecuta la funcion SumaLoca
16
Se termino de ejecutar SumaLoca

Ahora esta función decorada nos avisará sobre su ejecución o finalización.

Desde Python 2.4 en adelante se ha añadido Azucar a la cosa esto lo hace un lenguaje más dulce (Cuak!) ( a esto se le llama Azucar Sintáctica) y nos permite hacer lo mismo pero de la siguiente forma.

>>> @avisar
... def SumaLoca(a,b):
...     print a + b
...
>>> SumaLoca(10,6)
Se ejecuta la funcion SumaLoca
16
Se termino de ejecutar SumaLoca

Esta es una manera mucho más visual para hacerlo.

Una explicación mucho mejor al respecto van a encontrar en la edición Nro 4 de TheOriginalHackers [3] que está pronta a salir [4].

@staticmethod @classmethod

Leyendo un poco para arrancar esta seríe de Posts! es que entré al Blog de magmax y encontré la solución a algo que siempre me pregunté.  Por ejemplo para que quiero el parametro self en una método de una clase cuando ese método no toca nada de la clase. Bueno a explicarlo.

@staticmethod es un decorador que se utiliza para crear metodos que no requieren acceso a la clase principal.
@classmethod es decorador que reemplaza el paso de la variable self (que es una instancia de la clase) que es la predeterminada en cada metodo de una clase por la clase misma (o sea sin implementar).

Un ejemplo excelente de un buen uso acá [5]

Generadores 

Son funciones que devuelven resultados poco a poco y para esto lo hacen retornando un valor y retomando la ejecución desde ese punto en adelante generalmente dentro de alguna instrucción de bucle o repetición.

Ejemplo Kamikaze mío tiene que ver en crear un metodo que recorra urls y devuelva el titulo de la web de a poco.

from BeautifulSoup import BeautifulSoup as bs
import urllib

urls = ['http://www.google.com.ar', 'http://facebook.com', 'http://infobae.com.ar']

def recorrer_urls(urls):
    for url in urls:
        html = urllib.urlopen(url).read()
        soup = bs(html)
        yield soup.title

In [2]: recorrer_urls(urls)
Out[2]: 

In [3]: gen_urls = recorrer_urls(urls)

In [4]: gen_urls.next()
Out[4]: <title>Google</title>

In [5]: gen_urls.next()
Out[5]: <title id="pageTitle">¡Bienvenido a Facebook en Español!</title>

In [6]: gen_urls.next()
Out[6]: <title>"El Chapo" Guzmán - Tragedia de Once - WhatsApp - Telegram - Paritarias - Crisis política en Venezuela - Fotos - Infobae</title>

Esto es interesante cuando necesitemos recorrer una serie de datos pero no necesitamos que todos sean devueltos al mismo tiempo sino que se van generando dinamicamente uno a uno. [6]

[0] http://magmax.org/2013/09/30/python-avanzado.html
[1] http://www.juanjoconti.com.ar/2008/07/11/decoradores-en-python-i/
[2] http://es.wikipedia.org/wiki/Clausura_(inform%C3%A1tica)
[3] http://www.originalhacker.org/
[4] http://blog.deploshark.com.ar/2014/02/the-original-hacker-nro4.html
[5] http://stackoverflow.com/a/12179752
[6] http://www.alvarohurtado.es/generadores-en-python/

Gonzalo Martinez: The Original Hacker Nro4

Llegará prontamente una nueva edición de OriginalHacker[0], que continua con la misma dedicación en la explicación y con una exactitud teórica y práctica que asombra linea a linea.


Es tán copado y entretenido para quienes nos gusta hacer mover nuestro cerebro que cuando terminás de leerlo te quedás con ganas de más.

En esta entrega que sale a la Luz el próximo 25 de Febrero nos encontraremos con lo siguiente.


[Bash Scripting Avanzado] Bash un lenguaje que viene instalado por defecto en todos nuestros Linuxes del que Eugenia nos sigue mostrando su magía.

[Seguridad Informática] Se presenta y explica EuropioCode [1] una implementación de Seguridad respetando el modelo SAC, que también será brevemente explicado en el proceso.

[Ingeniería Inversa] Debo aceptar que esta es la sección que más estoy disfrutando en la primera nos involucramos en el proceso de desarrollo y sus pasos para aplicar "Ingenieria Inversa" como corresponde en nuestras aventuras de desarrollo.

[Ingenieria Inversa] El segundo amor de Eugenia (Python) y la mejor explicación que encontré (o que me encontró a mí) sobre Decoradores y Wrappers que dejará por el piso mi intención de explicar en mi publicación "Rockeandola Con Python Parte 2" (que saldrá en unos minutos o mañana no lo sé aún)

[EuropioEngine Lab] Como es aplicada la Capa de Seguridad desarollada para EuropioEngine. [2]

[0] originalhacker.org
[1] https://launchpad.net/europiocode
[2] http://www.europio.org/

Gonzalo Martinez: Rockeandola con Python Parte 1

Tomando como base un Post [0] muy interesante del que dejo referencia más abajo intentaré ahondar en mi propia explicación sobre lo que aprendí al respecto, ya que estoy en un momento en el que intento mejorar y profesionalizar mi forma de escribir código Python.

Métodos Mágicos [1]

What are magic methods? They're everything in object-oriented Python. They're special methods that you can define to add "magic" to your classes.
Estos métodos normalmente están encerrados entre "__" (doble guion bajo o underscore para los que saben inglés). Un ejemplo es __add__ que se llama cuando se hace entre dos objetos la operación de suma. En el Shell Interactivo de Python le pedimos un poco de ayuda sobre que hace el Entero 4 y nos dice lo siguiente

>>> help(4)
Help on int object:

class int(object)
 |  int(x[, base]) -> integer
(Resumido)
|  __add__(...)
|      x.__add__(y) <==> x+y

Entonces podríamos hacer cosas Interesantes o locas como por ejemplo

class Hombre(object):
    def __init__(self, nombre):
        self.nombre = nombre

    def __add__(self, Persona):
        if isinstance(Persona, Mujer):
            return Hijo()

class Mujer(object):
    def __init__(self, nombre):
        self.nombre = nombre

    def __add__(self, Persona):
        if isinstance(Persona, Hombre):
            return Hijo()

class Hijo(object):
    def __init__(self):
        self.nombre = raw_input('Despues de nueve meses has tenido un hijo\nPonle un nombre: ')

>>> from suma_clases import *
>>> juan = Hombre('Juan')
>>> martina = Mujer('Martina')
>>> hijo = juan + martina
Despues de nueve meses has tenido un hijo
Ponle un nombre: Sergio
>>> hijo.nombre
'Sergio'

Este es un ejemplo burdo pero imagínense las posibilidades? Hacer suma de objetos que cambien dinamicamente su comportamiento o contengan comportamientos nuevos según si se lo suma con tal o cual otro. Además de la legibilidad que le agrega hacer una suma como una suma y no con una funcion llamada sumar() o add(). Lo mismo se puede hacer con muchas otras cosas como por ejemplo para comparar si dos objetos son iguales. [2]

Se muestra el ejemplo de agregarle el eq a la clase mujer:
class Mujer():
(Resumido)
    def __eq__(self, Persona):
        if isinstance(Persona, Hombre):
            print 'Todos somos iguales'
            return True
        else:
            return False

>>> from suma_clases import *
>>> juan = Hombre('Juan')
>>> martina = Mujer('Martina')
>>> juan == martina
Todos somos iguales
True

Por lo que aprender a usar BIEN estos métodos mágicos seguramente te ayude a hacer hermosas APIs y código no solo más legible sino más bonito.

Otro cosa que me tocó hacer para un proyecto del trabajo es sobrecargar el __setattr__ de SQLObject para que haga un trigger o update en una tabla cuando se cambiaba cierta columna que es representada como una propiedad de esa clase.

Esto lo hice con el ejemplo que transcribo acá [3].

class Comment(SQLObject):
User = ForeignKey('TG_User')
Created = DateTimeCol(notNone=True, default=datetime.now())
Modified = DateTimeCol(notNone=True, default=datetime.now())
Subject = StringCol(length=200)
Body = StringCol()

def __setattr__( self, name, value ):
super( Comment, self ).__setattr__( name, value )
if name in self.sqlmeta.columns.keys():
super( Comment, self ).__setattr__( 'Modified', datetime.now() )

En mi caso además de modificar la fecha de actualización en la tabla debía agregar unos datos en una tabla que sirve como historial.

Atributos bajo demanda

En python todo funciona como fuera un diccionario por eso se pueden listar todos los atributos llamando al atributo de solo lectura llamada __dict__

>>> juan = Hombre('Juan')
>>> juan.__dict__
{'nombre': 'Juan'}
Usando ese atributo __dict__ podemos por ejemplo agregarle a esa instancia un atributo que no viene en la Clase de la que fue instanciada. Como por ejemplo
>>> juan.__dict__['nombre_falso'] = 'Pedro'
>>> juan.__dict__
{'nombre': 'Juan', 'nombre_falso': 'Pedro'}
>>> juan.nombre_falso
'Pedro'

Algo mucho más interesante para hacer es utilizarlo para hacer que una clase tenga como atributos cualquier cosa que se le pase como parámetros nombrados.

class Example(object): 
def __init__(self, **kwargs): 
self.__dict__.update(kwargs)

Que se usaría de esta manera.

>>> ej = Example(nombre='Gonzalo', perro='Chicho', facebook=True)
>>> ej.nombre
'Gonzalo'
>>> ej.perro
'Chicho'
>>> ej.facebook
True

El post de magmax es más largo y yo lo voy a partir en pedacitos para ver si además de decirlo con mis palabras lo puedo extender con experiencias propias. Asi que los veo en las siguientes partes.

[0] http://magmax.org/2013/09/30/python-avanzado.html
[1] http://www.rafekettler.com/magicmethods.html
[2] http://www.rafekettler.com/magicmethods.html#comparisons
[3] http://turbogears.org/1.0/docs/SQLObject/AutoUpdateField.html

Hernán Grecco: A new PyVISA release is around the corner and we need your help

PyVISA is a Python wrapper for the VISA library that enables controlling control all kinds of measurement equipment through GPIB, RS232, USB and Ethernet. It has served the instrumentation community very well since 2005 (that's Python 2.3!) and still does.

However, Python and the different supported platforms have changed a lot in the recent years. We think that PyVISA can use an update. Within the Lantz Project we did a small proof of principle of such update in visalib. Now we are taking what worked well and use it into PyVISA 1.5 (without changing the API!). In other words, PyVISA 1.5 brings several important changes in the underlying architecture without forcing you to change the programs.

The new architecture is summarized here and the comparison with the previous one is here. Briefly you get Python 3 support, Mac OS X support, a better way to find libraries in your platform, an isolated ctypes wrapper. But the most important change is that the VISA library is not opened on import anymore. You can still use the instrument and get_instruments_list helpers (although we encourage not to do it!), but under the hood they will only instantiate a VisaLibrary object when you need them. We think that this will lead to more explicit and clear code, easier to deploy and to upgrade. There other small goodies around. Take a look at the docs.

We really need your help before uploading this to PyPI as an stable release. PyVISA is all about interacting with your operating system (finding and locating the C library) and you instruments. With the variety of platforms around, it is very difficult to test. We are asking all users to install PyVISA from the github repository and test it on your programs. You can do it safely on a virtual environment:

$ virtualenv --system-site-packages pyvisa15
$ cd pyvisa15
$ source bin/activate
$ pip install -U https://github.com/hgrecco/pyvisa/zipball/master

or just use the last line (you can always revert back to the pyvisa version that you were using before)

Submit your bug reports, comments and suggestions in the Issue Tracker. We will address them promptly. We even have

Read the docs: http://pyvisa.readthedocs.org/
or fork the code: https:/https://github.com/hgrecco/pyvisa/

Joaquin Tita: InstantClick - JS library to speed up your website

Latency is inevitable with today’s internet architecture so InstantClick cheats by preloading links you are likely to click on.
Before visitors click on a link, they hover over that link. Between these two events, 200 ms to 300 ms usually pass by. InstantClick makes use of that time to preload the page, so that the page is already there when you click.
If you want your website to not be flooded by requests, you can set a delay before preloading starts when users hover a link. It will still feel instant.
If you don’t want any wasted request, you may preload on mousedown.

Gonzalo Martinez: Patrones y Tácticas Arquitecturales

Un patrón arquitectural


  • Es un paquete de decisiones de diseño que es encontrado repetidamente en la práctica.
  • tiene propiedades conocidas que permiten reusarlo, y
  • describe una clase de arquitecturas
Por que los patrones son (por definición) encontrados repetidamente en la práctica, uno no los inventa; uno los descubre.
Las tácticas son más simples que los patrones. Las tácticas tipicamente usan solo una simple estructura o mecanismo computacional, y están destinados a significar una simple fuerza arquitectónica. Por esta razón se les da un control más preciso a un arquitecto cuando hace decisiones de diseño de patrones, que tipicamente combina múltiples decisiones de diseño en un paquete. Las tácticas son los "bloques de construcción" de diseño a partir del cual los patrones arquitecturales son creados. Las tácticas son átomos y los patrones son moléculas. 

Un patrón arquitectural establece una relación entre ellos:
  • Un contexto. Una recurrente, situación común en el mundo que da a plantear un problema.
  • Un problema. El problema, apropiadamente generalizado, que surge en el contexto dado.
  • Una solución. Una resolución arquitectural exitosa a el problema.
Sistemas complejos exhiben múltiples patrones de una sola vez.

Los patrones pueden ser categorizados por el tipo de elementos dominante que muestran. patrones de módulos, muestran módulos. patrones de conectores-componentes muestran componentes y conectores. y los patrones de asignación muestran una combinación de elementos de software (módulos, componentes, conectores ) y elementos que no son de software. Los patrones más publicados son los patrones C&C, pero hay patrones de módulos y de asignación también. 

Un patrón es descrito como una solución a una clase de problemas en un contexto general. Cuando un patrón es elegido y aplicado, el contexto de esta aplicación se vuelve muy especifico. Un patrón documentado por lo tanto es poco especifico con respecto a la aplicación de una situación especifica. Podemos hacer un patrón más especifico a nuestro problema añadiéndole tácticas. Aplicando tácticas sucesivas es como pasar a través de un espacio de juego, y es un poco como el ajedrez: las consecuencias de el siguiente movimiento son importantes y observas varios movimientos por adelantado es útil.

Gonzalo Martinez: Aprendiendo Erlang parte 5 Listas por comprensión

Las listas por comprensión son maneras para construir y modificar listas. Ellos hacen que los programas sean cortos y fáciles de entender comparada a otras maneras de manipular listas. Que está basado en la idea de notación de conjuntos; Si alguna vez has tomado clases de matemáticas con la teoría de conjuntos o si alguna vez has mirado la notación matemática, tal vez conozcas como funciona esto. La notación de conjuntos básicamente te dice cómo construir un conjunto especificando las propiedades que sus miembros deben satisfacer. Las listas por comprensión son difíciles de entender en principio, pero vale la pena el esfuerzo. Ellas hacen el código limpio y corto, así que no dudes en intentarlo y escribir ejemplos hasta lo que entiendas.

Un ejemplo de notacion de conjuntos sería . Esa notación de conjuntos te dice que el resultado que buscas debería ser todos los números reales los cuales son igual a su propio cuadrado.El resultado de aquel conjunto debería ser {0,1}. Otra ejemplo de notación de conjuntos, más simple y abreviado sería {x : x > 0}. Aquí, buscaremos todos los números donde x > 0.

1> [2*N || N <- [1,2,3,4]]
[2,4,6,8]

Comparando con la notación mátematica a la de Erlang no hay tantos cambios. las llaves ({}) se convierten en corchetes ([]), los dos puntos (:) se convierten en dos pipes (||) y la palabra "en" se convierte en una flecha (<-) solamente cambiamos signos  y mantenemos la misma lógica. En el ejemplo anterior, cada valor de [1,2,3,4] secuencialmente coincide con el patrón N. La flecha actua exactamente como operador el "=", con la excepción que no lo hace lanzar excepciones.

También puede agregarle restricciones a la lista de comprensión usando operaciones que retornen valores booleanos. Si nosotros buscamos que todos los numeros seán pares sobre 10 de ellos, podríamos escribir algo como esto.

2> || X <- [1,2,3,4,5,6,7,8,9,10], X rem 2 =:= 0].
[2,4,6,8,10]

Donde X rem 2 =:= 0 chequea si un número es par. Las aplicaciones prácticas vienen cuando decidimos aplicar una función a cada elemento de una lista, forzando a respetar restricciones, etc. Como un ejemplo, digamos que tenemos un restaurante. Un cliente entra, ve nuestro menú y pregunta si el podría obtener los precios de todos los items que cuestan entre $3 a $10 con impuestos (digamos 7%).

3> RestaurantMenu = [{steak, 5.99}, {beer, 3.99}, {poutine, 3.50}, {kitten, 20.99}, {water, 0.00}].
[{steak,5.99},
 {beer,3.99},
 {poutine,3.5},
 {kitten,20.99},
 {water,0.0}]
4> [{Item, Price*1.07} || {Item, Price} <- RestaurantMenu, Price >= 3, Price =< 10].
[{steak,6.409300000000001},{beer,4.2693},{poutine,3.745}]

Por supuesto, los decimales no están redondeados en una manera legible, pero creo que lo entiendes. La receta para las listas de comprensión en Erlang es por lo tanto NuevaLista = [Expresion || Patron <- Lista, Condicion1, Condicion2, ... CondicionN]. La parte Patron <- Lista es llamada expresión Generador. Puedes tener más de uno.

5> [X+Y || X <- [1,2], Y <- [2,3]].
[3,4,4,5]

Esto corre las operaciones 1+2, 1+3, 2+2, 2+3. Asi que si quieres hacer la receta de las listas por comprensión más generica podrías obtener: NuevaLista = [Expresion || GeneradorExp1, GeneradorExp2, ..., GeneradorExpN, Condicion1, Condicion2, ..., CondicionM] . Nota que las expresiones generador son emparejadas con la coincidencia de patrones que funciona como filtro.

6> Clima = [{la_pampa, lluvioso}, {buenos_aires, tormenta}, {cordoba, niebla}, {tucuman, soleado}, {entre_rios, niebla}, {santa_cruz, nevado}].                                                                                           
[{la_pampa,lluvioso},
 {buenos_aires,tormenta},
 {cordoba,niebla},
 {tucuman,soleado},
 {entre_rios,niebla},
 {santa_cruz,nevado}]
7> LugaresConNiebla = [X || {X, niebla} <- Clima].
[cordoba,entre_rios]

Si un elemento en la lista Clima no coincide con el patrón {X, niebla}, este es simplemente ignorado en la lista de comprensión donde en una igualdad lanzaría una excepción.

Hay otro tipos de datos básicos que nos queda por ver, por ahora. Esta es una carácteristica sorprendente que hace fácil interpretar datos binarios.