Haskell: Sintaxis Básica
Mayo 10 2008 :: Haskell, Programación Funcional ::
Tipos y Funciones
:t Muestra el tipo de datos
Las funciones son tipos de datos (pensar en definición matematica)
mas2 a = a+2
:t mas2
mas2 :: (Num a) => a -> a
Debe leerse como si a es numérico, entonces, mas2 es una función de a en a. Pensar en f: A -> A
Para forzar un tipo, lo declaro al principio:
multiploDe2 :: Int -> Bool
multiploDe2 a = rem a 2 == 0
Funciones con mas de una variable.
multiplo :: (Integral a) => a -> a ->
Boolmultiplo a b = rem a b == 0
Para comprender mejor:
:t multiplo 10
multiplo 10 :: (Integral t) => t -> Bool
(O sea que al llenar la primer variable se retorna una función de el tipo de la segunda variable al tipo de retorno.)
Sintaxis de Funciones
Función definida en diferentes casos:
fibonacci :: Int -> Int
fibonacci a | a < 1 = error "Indefinida para ese valor"
| a == 1 || a == 2 = 1
| otherwise = fibonacci (a-1) + fibonacci (a-2)
Otra forma es:
prefix :: String -> String -> Bool
prefix [] ys = True
prefix (x:xs) [] = False
prefix (x:xs) (y:ys) = (x==y) && prefix xs ys
O una combinación
substring :: String -> String -> Bool
substring xs [] = False
substring xs (y:ys) | prefix xs (y:ys) = True
| otherwise = substring xs ys
Construcción de Conjuntos a partir de listas
Un ejemplo, el conjunto de los pares. x = 2k; k ∈ N
pares = map (*2) [1..]
Otro ejemplo Primos y compuestos (del libro)
prime :: Integer -> Bool
prime n | n < 1 = error "not positive integer"
| n == 1 = False
| otherwise = ldp n == n
ldp :: Integer -> Integer
ldp = ldpf primes
ldpf :: [Integer] -> Integer -> Integer
ldpf (p:ps) n | rem n p == 0 = p
| p^2 > n = n
| otherwise = ldpf ps n
primes :: [Integer]
primes = 2 : filter prime [3..]
composite :: Integer -> Bool
composite n = not (prime n)
composites :: [Integer]
composites = 4 : filter composite [5..]
Operadores Infix
(-) 5 3 ≡ 5 - 3
rem 10 3 ≡ 10 `rem` 3
Definición de un operador Infix ( “|” y “/” ya están definidos en prelude por eso use “//” )
divide :: Int -> Int -> Bool
divide a b = rem b a == 0
infix 1 //
(//) :: Int -> Int -> Bool
a // b = divide a b
Funciones auxiliares dentro de funciones
solveQdr :: Float -> Float -> Float -> (Float, Float)
solveQdr a b c | a == 0 = error "No es Quadratica"
| d<0 = error "No hay solucion en los Reales"
| otherwise = ( (-b + sqrt d ) / 2*a, (-b - sqrt d ) / 2*a)
where d = (b^2)-(4*a*c)
Otra opcion (let … in)
solveQdr :: Float -> Float -> Float -> (Float, Float)
solveQdr a b c = if a == 0 then error "No es Quadratica"
else let d = b^2 - 4*a*c in
if d<0 then error "No hay solucion en los reales"
else ( (-b + sqrt d ) / 2*a, (-b - sqrt d ) / 2*a)
Expresiones Lambda
Uso Básico
por2 :: Integer -> Integer
por2 = (\ x -> x*2 )
(\x -> x+1) 8
9
Pasaje de una expresión Lambda como parámetro a una función (es como pasar una función)
infix 1 ==>
(==>) :: Bool -> Bool -> Bool
True ==> x = x;
False ==> x = True;
infix 1 <=>
(<=>) :: Bool -> Bool -> Bool
x <=> y = x == y
infixr 2 <+>
(<+>) :: Bool -> Bool -> Bool
x <+> y = x /= y
{- Equivalencias logicas -}
logEquiv1 :: (Bool -> Bool) -> (Bool -> Bool) -> Bool
logEquiv1 bf1 bf2 = (bf1 True <=> bf2 True) && (bf1 False <=> bf2 False)
logEquiv2 :: (Bool -> Bool -> Bool) -> (Bool -> Bool -> Bool) -> Bool
logEquiv2 bf1 bf2 = and [(bf1 p q <=> bf2 p q) | p <- [True, False],
q <- [True, False]]
logEquiv3 :: (Bool -> Bool -> Bool -> Bool) -> (Bool -> Bool -> Bool -> Bool) -> Bool
logEquiv3 bf1 bf2 = and [(bf1 p q r <=> bf2 p q r) | p <- [True, False],
q <- [True, False],
r <- [True, False]]
{- Idempotencia -}
logEquiv1 (\p -> p) (\p -> p || p)
True
{- Doble Negación -}
logEquiv1 (\p -> p) (\p -> not (not p))
True
{- De Morgan -}
logEquiv2 (\p q -> not (p && q)) (\p q -> not p || not q)
True
{- Contrareciproco -}
logEquiv2 (\p q -> p ==> q) (\p q -> not q ==> not p)
True
{- Distributiva -}
logEquiv3 (\p q r -> (p || q) && r) (\p q r -> (p && r) || (q && r))
True
Expresiones mas complejas
every , some :: [a] -> (a -> Bool) -> Bool
every xs p = all p xs
some xs p = any p xs
(\x -> some [1,2,3] (\y -> x==y^2)) {- Verifica si un numero es el cuadrado de 1, 2 o 3 -}
(\x -> some [1,2,3] (\y -> x==y^2)) 4
True
:t (\x -> some [1,2,3] (\y -> x==y^2))
(\x -> some [1,2,3] (\y -> x==y^2)) :: (Num a) => a -> Bool
every [1,4,9] (\x -> some [1,2,3] (\y -> x==y^2))
True
List comprehension, And, Or
{- valid 3 por List comprehension -}
valid3 :: (Bool -> Bool -> Bool -> Bool) -> Bool
valid3 bf = and [ bf p q r | p <- [True, False],
q <- [True, False],
r <- [True, False] ]
{- and es Conjuncion generalizada sobre una lista (Retorna True si todos son True),
p <- Es List Comprehension
:t and
and :: [Bool] -> Bool
Existe tambien or que es Disyunción generalizada sobre la lista. (Retorna True si al menos uno es True)
-}
Otra forma.
[ x | x <- [1..10], prime (x+5)]
[2,6,8]
Composición de Funciones
por3 :: Int -> Int
por3 x = x*3
divisiblePor2 :: Int -> Bool
divisiblePor2 x = rem x 2 == 0
:t (divisiblePor2 . por3)
(divisiblePor2 . por3) :: Int -> Bool
(divisiblePor2 . por3) 4
True
(divisiblePor2 . por3) 5
False
Referencias
Capitulo 1,2,3 de The Haskell Road To Logic, Math and Programming; Doets, Van Eijck; King´s College London Publications; 2004Autor: Emiliano Martínez Luque.


Deja un Comentario
Guía de los comentarios
Tu Email es requerido pero no sera publicado.
Podes usar los siguientes tags de HTML:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>Si no comentastes antes tu comentario debera ser aprovado antes de que se lo muestre. Perdón, pero hay demasiado spam.