« Elm: Señales « || Inicio || » Elm: Definiendo Tipos… »

Elm: Sintaxis Básica

Última modificación: 25 de Noviembre de 2016, y ha tenido 60 vistas

These icons link to social bookmarking sites where readers can share and discover new web pages.
  • BarraPunto
  • Del.icio.us
  • Digg
  • email
  • Facebook
  • Google
  • LinkedIn
  • PDF
  • Reddit
  • Slashdot
  • Twitter

Este es un pequeño resumen de la sintaxis básica de Elm.

Comentarios

Comentarios de una sola línea. Puede empezar en cualquier parte de la línea:

-- Una línea entera comentada
main = show "Hola" -- Un comentario posterior

Comentarios de bloques:

{- Un bloque comentado
   {- Puede haber bloques comentados dentro -}
-} 

Un truco habitual para comentar y descomentar rápidamente en Elm consiste en lo siguiente:

{--}
suma x y = x + y
--} 

Para comentar/descomentar el bloque completo basta añadir o quitar el corchete } en la primer línea (pruébalo en el editor on-line).

Literales

-- Booleanos
True  : Bool
False : Bool

42    : number  -- Int o Float dependerá del uso
3.14  : Float

'a'   : Char
"abc" : String

-- String Multilínea
"""
Puede ser útil también para textos 
que contienen palabras "entrecomilladas".
"""

La manipulación de líterales se hace de la forma usual:

True && not (True || False)
(2 + 4) * (4^2 - 9)
"abc" ++ "def"

Listas

Como en muchos lenguajes funcionales, las listas son las estructuras de datos más comunes en Elm, cubriendo el mismo papel que en otros lenguajes hacen los vectores (arrays). Las listas pueden mantener muchos valores simultáneamente, una cantidad indeterminada, pero todos del mismo tipos. Las funciones más habituales para trabajar con listas están definidas en al librería List:

Siguen el formato estándar de muchos lenguajes: [ ] para denotar listas, :: para añadir elementos a listas, .. para rangos:

[1,2,3,4]
1 :: [2,3,4]
1 :: 2 :: 3 :: 4 :: []
[1..4]

Condicionales

La estructura de los condicionales en Elm sigue el patrón: if-then-else

if nota >= 5 then "Aprobado" else "Suspenso"

Y si tuviéramos que encadenar varias estructuras de estas, podemos usar la expresión:

if key == 40 then
n+1
else if key == 38 then
n-1 else
n

También tenemos expresiones de tipo case para facilitar el uso de patrones en las estructuras algebráicas que manipulamos:

case maybe of
  Just xs -> xs
  Nothing -> []

case xs of
  hd::tl -> Just (hd,tl)
  []     -> Nothing

case n of
  0 -> 1
  1 -> 1
  _ -> fib (n-1) + fib (n-2) 

Se ha de tener cuidado con la identación, ya que es la que define los bloques de instrucciones que se consideran juntos.

Registros

Un registros es un conjunto de pares clave-valor. Son extremadamente útiles y comunes en Elm, así que conviene manejarlos con soltura. Una primera aproximación a los registros la podemos obtener a partir del siguiente código:

punto = { x = 3, y = 4 }       -- crea un registro con dos campos, x e y

punto.x                        -- acceso a uno de los campos
map .x [punto,{x=0,y=0}]       -- el acceso se puede usar como una función más

{ punto | z = 12 }             -- añadir un campo
{ punto - x | x = 6 }          -- actualizar un campo

lib = { id x = x }             -- Los campos pueden ser polimórficos. Aquí almacenamos una función
(lib.id 42 == 42)
(lib.id [] == [])    

Cuando se definan funciones que trabajan sobre registros, se puede hacer coincidencia de patrones sobre sus campos. Por ejemplo:

primerCuadrante {x,y} = x>0 && y >0 

Funciones

Se definen de la forma habitual, y deben empezar con minúsculas:

cuadrado n = n^2

hipotenusa a b = sqrt (square a + square b)
    
distancia (a,b) (x,y) = hipotenusa (a-x) (b-y)

También admite funciones anónimas:

cuadrado = \n -> n^2
cuadrados = map (\n -> n^2) [1..100]

Operadores Infijos

Se pueden crear operadores infijos (basta poner el nombre del operador entre parentesis cuando se define), y asignarles una precedencia de aplicación (que va de 0 a 9, donde 9 es la mayor). Por defecto se les da una precedencia de 9 y son asociativos por la izquierda (ambas cosas son configurables). No se pueden reescribir los operadores que vienen por defecto. Por ejemplo, si definimos:

(?) : Maybe a -> a -> a
(?) maybe default =
  Maybe.withDefault default maybe

Podemos cambiar su asociatividad y precedencia con:

infixr 8 ?

Los operadores (<|) y (|>) definen la aplicabilidad de funciones, y pueden servir para reducir paréntesis:

f <| x = f x
x |> f = f x

De forma que las dos siguientes definiciones son equivalentes:

puntito =
  scale 2 (move (20,20) (filled blue (circle 10)))

puntito' =
  circle 10
    |> filled blue
    |> move (20,20)
    |> scale 2

De forma análoga, los operadores (<<) y (>>) se corresponden con la composición de funciones.

Expresiones Let

El formato de una expresión let es como sigue:

let n = 42
    (a,b) = (3,4)
    {x,y} = { x=3, y=4 }
    cuadrado n = n * n
in
    cuadrado a + cuadrado b

Al igual que las condicionales, la identación es importante, de forma que en el bloque las definiciones han de estar alineadas.

Existen muchas funciones que son equivalentes y que se pueden aplicar de muchas formas:

append xs ys = xs ++ ys = (++) xs ys = xs `append` ys = (append xs) ys = ((++) xs) ys

El siguente operador infijo crea tuplas y también admite usarlo de forma más natural y poner todas las comas que se desee:

(,) 1 2              == (1,2)
(,,,) 1 True 'a' []  == (1,True,'a',[])

Las tuplas son otra de las estructuras más comunes. A diferencia de las listas, solo pueden mantener una cantidad prefijada de valores, pero cada valor puede ser de un tipo distinto.

Módulos

La forma de definir un módulo es:

module MiModulo where
...

Para importar los módulos tenemos varias opciones, en cada una de ellas se acompaña al lado cómo deben realizarse las llamadas a las funciones de los módulos:

-- importación cualificada
import List                    -- List.map, List.foldl
import List as L               -- L.map, L.foldl

-- importación abierta
import List exposing (..)               -- map, foldl, concat, ...
import List exposing ( map, foldl )     -- map, foldl, List.concat,...

import Maybe exposing ( Maybe )         -- Maybe
import Maybe exposing ( Maybe(..) )     -- Maybe, Just, Nothing
import Maybe exposing ( Maybe(Just) )   -- Maybe, Just 

Los nombres de los módulos han de coincidir con sus nombres de fichero, de forma que el módulo Parser.Utils necesita estar en el fichero Parser/Utils.elm.

Signaturas

Se establecen con : y se separan argumentos y resultados con ->

valor : Int
valor = 42

factorial : Int -> Int
factorial n = product [1..n]

uneNombre : String -> a -> { a | nombre:String }
uneNombre nombre registro = { registro | nombre = nombre }

Si se han usado alias de tipos (que empiezan por mayúsculas), se pueden usar estas definiciones en las signaturas:

type alias Nombre = String
type alias Edad = Int

info : (Nombre,Edad)
info = ("Adán", 28)

type alias Punto = { x:Float, y:Float }

origen : Punto
origen = { x=0, y=0 }

« Elm: Señales « || Inicio || » Elm: Definiendo Tipos… »