Translate

miércoles, 22 de abril de 2020

Elementos básicos en Haskell, Parte 2

Veamos algunos elementos más básicos (y no tan básicos) de Haskell a través de la comparación con otros lenguajes. No entraremos en detalles sobre las construcciones de Haskell, solo mostraremos las similitudes con las construcciones de los lenguajes que podamos conocer.

En JavaScript, las funciones suelen ser bloques de código:

    function roots(a,b,c) {
        det2 = b*b-4*a*c;
        det  = sqrt(det2);
        rootp = (-b + det)/a/2;
        rootm = (-b - det)/a/2;
        return [rootm,rootp]
    }

En Haskell, escribiríamos esta función de la siguiente manera:

    roots a b c = 
        let
            det2 = b*b-4*a*c;
            det  = sqrt(det2);
            rootp = (-b + det)/a/2;
            rootm = (-b - det)/a/2;
        in
            [rootm,rootp]

Tenga en cuenta que la construcción let ... in ... es una expresión, por lo que devuelve un valor. Por eso no hay necesidad de una palabra clave de return.

En Python podríamos escribir una función con una condición como esta:

def max(x,y):
    if x > y:
        return x
    else:
        return y

Por supuesto, Haskell también tiene una construcción if-then:

    max x y = 
        if x > y
            then x
            else y

Una vez más, la construcción if ... then ... else ... es una expresión, por lo que devuelve un valor.

Muchos lenguajes proporcionan una declaración de caso para condiciones con más de dos opciones. Por ejemplo, Ruby proporciona una expresión de caso:

    Red = 1
    Blue = 2
    Yellow = 3

    color = set_color();
    action = case color 
        when Red then action1()
        when Blue then action2()
        when Yellow then action3()
    end

En Haskell, el caso funciona y se ve similar:

    data Color = Red | Blue | Yellow

    color = set_color
    action = case color of
        Red -> action1
        Blue -> action2
        Yellow -> action3

Sin embargo, tenga en cuenta cómo usamos el tipo como el valor para decidir el caso, donde en otros lenguajes necesitamos definir algún tipo de enumeración.

En Java y C ++ hay tipos de datos genéricos (también conocidos como tipos de plantillas, generic o template en ingles), como:

    Map<String,Integer> set = new HashMap<String,Integer>();

En Haskell, escribirías esto de la siguiente manera:

    set :: Data.Map.Map String Integer 
    set = Data.Map.empty

La principal diferencia es, por supuesto, que el conjunto en Haskell no es un objeto sino una variable inmutable, por lo que en Java haríamos :

    set.put("Answer",42)

En Haskell haríamos :

    set' = Data.Map.insert "Answer" 42 set

Debido a que en Haskell las variables son inmutables, el valor de retorno de la llamada de inserción está vinculado a una nueva variable en lugar de actualizar la variable en su lugar como en Java.