Este artículo describe las características del lenguaje de programación Haskell .
Ejemplos
Factorial
Un ejemplo sencillo que se usa a menudo para demostrar la sintaxis de los lenguajes funcionales es la función factorial para enteros no negativos, que se muestra en Haskell:
factorial :: Entero -> Entero factorial 0 = 1 factorial n = n * factorial ( n - 1 )O en una sola línea:
factorial n = si n > 1 entonces n * factorial ( n - 1 ) sino 1Esto describe el factorial como una función recursiva, con un único caso base que termina. Es similar a las descripciones de factoriales que se encuentran en los libros de texto de matemáticas. Gran parte del código Haskell es similar a la notación matemática estándar en cuanto a facilidad de uso y sintaxis.
La primera línea de la función factorial describe el tipo de esta función; si bien es opcional, se considera una buena práctica [ 1 ] incluirla. Se puede leer como la función factorial ( factorial) tiene tipo ( ::) de entero a entero ( Integer -> Integer). Es decir, toma un entero como argumento y devuelve otro entero. El tipo de una definición se infiere automáticamente si no se proporciona ninguna anotación de tipo.
La segunda línea se basa en la coincidencia de patrones , una característica importante de Haskell. Cabe destacar que los parámetros de una función no se encuentran entre paréntesis, sino separados por espacios. Cuando el argumento de la función es 0 (cero), devuelve el entero 1 (uno). En todos los demás casos, se intenta la tercera línea. Esta es la recursión , que ejecuta la función repetidamente hasta alcanzar el caso base.
Utilizando la productfunción de Prelude, una serie de pequeñas funciones análogas a la biblioteca estándar de C , y utilizando la sintaxis de Haskell para secuencias aritméticas, la función factorial se puede expresar en Haskell de la siguiente manera:
factorial n = producto [ 1 .. n ]Aquí [1..n]denota la secuencia aritmética 1, 2, …, n en forma de lista. Usando la función Prelude enumFromTo, la expresión [1..n]se puede escribir como enumFromTo 1 n, lo que permite expresar la función factorial como
factorial n = producto ( enumFromTo 1 n )que, utilizando el operador de composición de funciones (expresado como un punto en Haskell) para componer la función producto con la función de enumeración currificada se puede reescribir en estilo sin puntos : [ 2 ]
factorial = producto . enumFromTo 1En el intérprete de Hugs, a menudo es necesario definir la función y usarla en la misma línea separada por un punto whereo coma let. inPor ejemplo, para probar los ejemplos anteriores y ver la salida 120:
sea { factorial n | n > 0 = n * factorial ( n - 1 ); factorial _ = 1 } en factorial 5o
factorial 5 donde factorial = producto . enumFromTo 1El intérprete GHCi no tiene esta restricción y las definiciones de funciones se pueden ingresar en una sola línea (con la letsintaxis sin la inparte) y referenciarse posteriormente.
Ejemplos más complejos
Calculadora
En el código fuente de Haskell inmediatamente debajo, ::se puede leer como "tiene tipo"; a -> bse puede leer como "es una función de a a b". (Por lo tanto, el Haskell se puede leer como " tiene tipo de una función de cadenas a listas de flotantes".) En la segunda línea, el signo igual se puede leer como "puede ser"; por lo tanto, varias líneas con se pueden leer como múltiples valores posibles para , dependiendo de la circunstancia detallada en cada línea.calc :: String -> [Float]calccalc = ...calc = ...calc
Una calculadora simple de notación polaca inversa expresada con la función de orden superiorfoldl cuyo argumento f se define en una cláusula where utilizando coincidencia de patrones y la clase de tipo Read :
calc :: String -> [ Float ] calc = foldl f [] . words where f ( x : y : zs ) "+" = ( y + x ) : zs f ( x : y : zs ) "-" = ( y - x ) : zs f ( x : y : zs ) "*" = ( y * x ) : zs f ( x : y : zs ) "/" = ( y / x ) : zs f ( x : y : zs ) "FLIP" = y : x : zs f zs w = read w : zsLa lista vacía es el estado inicial, y f interpreta una palabra a la vez, ya sea como el nombre de una función, tomando dos números del principio de la lista y volviendo a insertar el resultado, o analizando la palabra como un número de punto flotante y añadiéndolo al principio de la lista.
secuencia de Fibonacci
La siguiente definición produce la lista de números de Fibonacci en tiempo lineal:
fibs = 0 : 1 : zipWith ( + ) fibs ( tail fibs )La lista infinita se genera mediante corecursión : los últimos valores de la lista se calculan bajo demanda a partir de los dos elementos iniciales, 0 y 1. Este tipo de definición se basa en la evaluación perezosa , una característica importante de la programación en Haskell. Para ilustrar cómo evoluciona la evaluación, el siguiente ejemplo muestra los valores de fibs y tail fibs después del cálculo de seis elementos y muestra cómo zipWith (+) ha generado cuatro elementos y procede a generar el siguiente:
fibs = 0 : 1 : 1 : 2 : 3 : 5 : ... + + + + + + Fibs de cola = 1 : 1 : 2 : 3 : 5 : ... = = = = = = zipWith ... = 1 : 2 : 3 : 5 : 8 : ... fibs = 0 : 1 : 1 : 2 : 3 : 5 : 8 : ...
La misma función, escrita utilizando la sintaxis de comprensión de listas paralelas del compilador Glasgow Haskell (las extensiones de GHC deben habilitarse mediante una bandera especial de la línea de comandos, en este caso -XParallelListComp , o iniciando el archivo fuente con ):{-# LANGUAGE ParallelListComp #-}
fibs = 0 : 1 : [ a + b | a <- fibs | b <- tail fibs ]o con comprensiones de listas regulares :
fibs = 0 : 1 : [ a + b | ( a , b ) <- zip fibs ( tail fibs ) ]o autorreferencial directa:
fibs = 0 : 1 : siguiente fibs donde siguiente ( a : t @ ( b : _ )) = ( a + b ) : siguiente tCon función generadora con estado :
fibs = next ( 0 , 1 ) donde next ( a , b ) = a : next ( b , a + b )o con unfoldr:
fibs = unfoldr ( \ ( a , b ) -> Just ( a , ( b , a + b ))) ( 0 , 1 )o scanl:
fibs = 0 : scanl ( + ) 1 fibsUtilizando la recursión de datos con el combinador de punto fijo predefinido de Haskell :
fibs = fix ( \ xs -> 0 : 1 : zipWith ( + ) xs ( tail xs )) -- zipWith version = fix (( 0 : ) . ( 1 : ) . ( zipWith ( + ) <*> tail )) -- igual que arriba, pointfree = fix (( 0 : ) . scanl ( + ) 1 ) -- scanl versionFactorial
El factorial que vimos anteriormente se puede escribir como una secuencia de funciones:
factorial n = foldr (( . ) . ( * )) id [ 1 .. n ] $ 1 -- factorial 5 == ((1*) .) ( ((2*) .) ( ((3*) .) ( ((4*) .) ( ((5*) .) id )))) 1 -- == (1*) . (2*) . (3*) . (4*) . (5*) . id $ 1 -- == 1* ( 2* ( 3* ( 4* ( 5* ( id 1 )))))factorial n = foldr (( . ) . ( * )) ( const 1 ) [ 1 .. n ] $ () -- factorial 5 == ((1*) .) ( ((2*) .) ( ((3*) .) ( ((4*) .) ( ((5*) .) (const 1) )))) () -- == (1*) . (2*) . (3*) . (4*) . (5*) . const 1 $ () -- == 1* ( 2* ( 3* ( 4* ( 5* ( const 1 () )))))factorial n = foldr (( $ ) . ( * )) 1 [ 1 .. n ] = foldr ( $ ) 1 $ map ( * ) [ 1 .. n ] -- factorial 5 == ((1*) $) ( ((2*) $) ( ((3*) $) ( ((4*) $) ( ((5*) $) 1 )))) -- == (1*) $ (2*) $ (3*) $ (4*) $ (5*) $ 1 -- == 1* ( 2* ( 3* ( 4* ( 5* 1 ))))Más ejemplos
Números de Hamming
Una función extraordinariamente concisa que devuelve la lista de números de Hamming en orden:
hamming = 1 : map ( 2 * ) hamming ` unión ` map ( 3 * ) hamming ` unión ` map ( 5 * ) hammingAl igual que las diversas fibssoluciones mostradas anteriormente, esta utiliza la corecursión para generar una lista de números bajo demanda, partiendo del caso base de 1 y construyendo nuevos elementos basándose en la parte precedente de la lista.
Aquí la función unionse usa como operador encerrándola entre comillas invertidas. Sus casecláusulas definen cómo fusiona dos listas ascendentes en una lista ascendente sin elementos duplicados, representando conjuntos como listas ordenadas. Su función complementaria minusimplementa la diferencia de conjuntos :
Es posible generar únicamente los múltiplos únicos para un funcionamiento más eficiente. Dado que no hay duplicados, no es necesario eliminarlos.
smooth235 = 1 : foldr ( \ p s -> fix $ mergeBy ( < ) s . map ( p * ) . ( 1 : )) [] [ 2 , 3 , 5 ] donde fix f = x donde x = f x -- combinador de punto fijo, con comparticiónEsto utiliza la función más eficiente mergeque no se preocupa por los duplicados (también utilizada en la siguiente función mergesort):
mergeBy menos xs ys = merge xs ys donde merge xs [] = xs merge [] ys = ys merge ( x : xs ) ( y : ys ) | menos y x = y : merge ( x : xs ) ys | de lo contrario = x : merge xs ( y : ys )Cada barra vertical ( |) inicia una cláusula de guarda con una expresión de guarda antes del =signo y la definición correspondiente después, que se evalúa si la guarda es verdadera.
Mergesort
Aquí se muestra una ordenación por fusión ascendente , definida mediante la función de orden superioruntil :
mergesortBy less [] = [] mergesortBy less xs = head $ until ( null . tail ) ( pairwise $ mergeBy less ) [[ x ] | x <- xs ]f por pares ( a : b : t ) = f a b : f por pares t f por pares t = tNúmeros primos
La definición matemática de números primos se puede traducir prácticamente palabra por palabra a Haskell:
-- "Enteros mayores que 1 que no pueden ser divididos por un entero menor mayor que 1" -- primes = { n ∈ [2..] | ~ ∃ d ∈ [2..n-1] ⇒ rem nd = 0 } -- = { n ∈ [2..] | ∀ d ∈ [2..n-1] ⇒ rem nd ≠ 0 }primos = [ n | n <- [ 2 .. ], todos ( \ d -> rem n d /= 0 ) [ 2 .. ( n - 1 )] ]Este método encuentra números primos mediante división por tanteo . Cabe destacar que no está optimizado para la eficiencia y tiene un rendimiento muy bajo. Un poco más rápido (pero aún muy lento) [ 3 ] es este código de David Turner :
primos = criba [ 2 .. ] donde criba ( p : xs ) = p : criba [ x | x <- xs , rem x p /= 0 ]El algoritmo de división de ensayos óptimo es mucho más rápido.
primos = 2 : [ n | n <- [ 3 .. ], todos (( > 0 ) . rem n ) $ tomarMientras (( <= n ) . ( ^ 2 )) primos ]o un tamiz ilimitado de Eratóstenes con tamizado postergado en etapas, [ 4 ]
primos = 2 : criba primos [ 3 .. ] donde criba ( p : ps ) ( span ( < p * p ) -> ( h , t )) = h ++ criba ps ( menos t [ p * p , p * p + p .. ])o la implementación de tamiz combinado de Richard Bird , [ 5 ]
-- "Enteros mayores que 1 sin ningún número compuesto que -- se encuentran mediante la enumeración de los múltiplos de cada primo" primos = 2 : menos [ 3 .. ] ( foldr ( \ ( m : ms ) r -> m : unión ms r ) [] [[ p * p , p * p + p .. ] | p <- primos ])o una variante de plegado tipo árbol aún más rápida [ 6 ] con una complejidad temporal casi óptima (para un código basado en listas) y una complejidad espacial muy baja lograda a través de la producción recursiva multietapa telescópica de números primos:
primos = 2 : _Y (( 3 : ) . menos [ 5 , 7 .. ] . _U . map ( \ p -> [ p * p , p * p + 2 * p .. ])) donde -- combinador Y no compartido: _Y g = g ( _Y g ) -- (g (g (g (g (...))))) -- unión grande ~= nub.sort.concat _U (( x : xs ) : t ) = x : ( unión xs . _U . unión por pares ) tTrabajando en matrices por segmentos entre cuadrados consecutivos de números primos, es
import Data.Array import Data.List ( tails , inits )primos = 2 : [ n | ( r : q : _ , px ) <- zip ( colas ( 2 : [ p * p | p <- primos ])) ( init primos ), ( n , True ) <- assocs ( accumArray ( \ _ _ -> False ) True ( r + 1 , q - 1 ) [ ( m , () ) | p <- px , s <- [ div ( r + p ) p * p ] , m <- [ s , s + p .. q - 1 ] ] ) ]El código más corto posible es probablemente . Es bastante lento. nubBy (((>1) .) . gcd) [2..]
Sintaxis
Disposición
Haskell permite usar la indentación para indicar el comienzo de una nueva declaración. Por ejemplo, en una cláusula where :
producto xs = prod xs 1 donde prod [] a = a prod ( x : xs ) a = prod xs ( a * x )Las dos ecuaciones para la función anidadaprod están alineadas verticalmente, lo que permite omitir el separador de punto y coma. En Haskell, la indentación se puede usar en varias construcciones sintácticas, incluyendo do, let, case, class, y instance.
El uso de la indentación para indicar la estructura del programa tiene su origen en el lenguaje ISWIM de Peter J. Landin , donde se denominaba regla de espacio en blanco . Posteriormente, Miranda la adoptó , y Haskell adoptó una versión similar (aunque bastante más compleja) de la regla de espacio en blanco de Miranda, denominada "layout". Otros lenguajes que adoptaron una sintaxis sensible a los caracteres de espacio en blanco son Python y F# .
El uso de la disposición en Haskell es opcional. Por ejemplo, la función productanterior también se puede escribir de la siguiente manera:
producto xs = prod xs 1 donde { prod [] a = a ; prod ( x : xs ) a = prod xs ( a * x ) }La llave de apertura explícita después de la wherepalabra clave indica que las declaraciones separadas usarán punto y coma explícitos, y la lista de declaraciones terminará con una llave de cierre explícita. Una de las razones para querer admitir delimitadores explícitos es que facilita la generación automática de código fuente en Haskell .
La regla de diseño de Haskell ha sido criticada por su complejidad. En particular, la definición establece que si el analizador sintáctico encuentra un error de análisis durante el procesamiento de una sección de diseño, debe intentar insertar una llave de cierre (la regla de "error de análisis"). Implementar esta regla en una combinación tradicional de análisis sintáctico y léxico requiere una cooperación bidireccional entre el analizador sintáctico y el analizador léxico, mientras que en la mayoría de los lenguajes, estas dos fases pueden considerarse de forma independiente.
Llamadas a funciones
Aplicar una función fa un valor xse expresa simplemente como f x.
Haskell distingue sintácticamente las llamadas a funciones de los operadores infijos, pero no semánticamente. Los nombres de funciones compuestos por signos de puntuación pueden usarse como operadores, al igual que otros nombres de funciones si están entre comillas invertidas; y los operadores pueden usarse en notación prefija si están entre paréntesis.
Este ejemplo muestra las formas en que se pueden llamar a las funciones:
sumar a b = a + bdiez1 = 5 + 5 diez2 = ( + ) 5 5 diez3 = sumar 5 5 diez4 = 5 ` sumar ` 5Las funciones que se definen tomando varios parámetros siempre se pueden aplicar parcialmente. Los operadores binarios se pueden aplicar parcialmente utilizando la notación de secciones :
diez5 = ( + 5 ) 5 diez6 = ( 5 + ) 5 sumar cinco = ( 5 + ) diez7 = sumar cinco 5Comprensión de listas
Consulte List comprehension#Overview para ver el ejemplo en Haskell.
Coincidencia de patrones
La coincidencia de patrones se utiliza para hacer coincidir los diferentes constructores de tipos de datos algebraicos. A continuación se muestran algunas funciones, cada una de las cuales utiliza la coincidencia de patrones en cada uno de los siguientes tipos:
-- Esta firma de tipo indica que empty toma una lista que contiene cualquier tipo y devuelve un booleano empty :: [ a ] -> Bool empty ( x : xs ) = False empty [] = True-- Devolverá un valor de un Maybe a, dado un valor predeterminado en caso de que se encuentre un Nothing fromMaybe :: a -> Maybe a -> a fromMaybe x ( Just y ) = y fromMaybe x Nothing = xisRight :: Either a b -> Bool isRight ( Right _ ) = True isRight ( Left _ ) = FalsegetName :: Persona -> Cadena getName ( Persona nombre _ _ ) = nombreobtenerSexo :: Persona -> Sexo obtenerSexo ( Persona _ sexo _ ) = sexogetAge :: Persona -> Int getAge ( Persona _ _ edad ) = edadUtilizando las funciones anteriores, junto con la mapfunción, podemos aplicarlas a cada elemento de una lista para ver sus resultados:
map empty [[ 1 , 2 , 3 ], [] ,[ 2 ],[ 1 .. ]] -- devuelve [False,True,False,False]map ( fromMaybe 0 ) [ Just 2 , Nothing , Just 109238 , Nothing ] -- devuelve [2,0,109238,0]map isRight [ Left "hola" , Right 6 , Right 23 , Left "mundo" ] -- devuelve [Falso, Verdadero, Verdadero, Falso]map getName [ Person "Sarah" Female 20 , Person "Alex" Male 20 , tom ] -- devuelve ["Sarah", "Alex", "Tom"], usando la definición de tom anterior- Tipos abstractos
- Liza
Tuplas
En Haskell, las tuplas se pueden usar para almacenar un número fijo de elementos. Se utilizan para agrupar datos de diferentes tipos:
cuenta :: ( Cadena , Entero , Doble ) -- El tipo de una tupla de tres elementos, que representa -- un nombre, saldo y tasa de interés cuenta = ( "John Smith" , 102894 , 5.25 )Las tuplas se utilizan comúnmente en las funciones zip* para colocar elementos adyacentes en listas separadas juntos en tuplas (zip4 a zip7 se proporcionan en el módulo Data.List):
-- Definición de la función zip. Otras funciones zip* se definen de forma similar zip :: [ x ] -> [ y ] -> [( x , y )] zip ( x : xs ) ( y : ys ) = ( x , y ) : zip xs ys zip _ _ = []zip [ 1 .. 5 ] "hola" -- devuelve [(1,'h'),(2,'e'),(3,'l'),(4,'l'),(5,'o')] -- y tiene tipo [(Entero, Carácter)]zip3 [ 1 .. 5 ] "hola" [ Falso , Verdadero , Falso , Falso , Verdadero ] -- devuelve [(1,'h',Falso),(2,'e',Verdadero),(3,'l',Falso),(4,'l',Falso),(5,'o',Verdadero)] -- y tiene tipo [(Entero,Carácter,Booleano)]En el compilador GHC, las tuplas se definen con tamaños que van desde 2 elementos hasta 62 elementos.
Espacios de nombres
En la sección § Ejemplos más complejos anterior, calcse utiliza en dos sentidos, mostrando que hay un espacio de nombres de clases de tipos de Haskell y también un espacio de nombres para valores:
- una clase de tipo Haskell para
calc. El dominio y el rango se pueden denotar explícitamente en una clase de tipo Haskell. - un valor, fórmula o expresión de Haskell para
calc.
Clases de tipos y polimorfismo
Tipos de datos algebraicos
Los tipos de datos algebraicos se utilizan ampliamente en Haskell. Algunos ejemplos de estos son la lista integrada Maybey Eitherlos tipos:
-- Una lista de 'a's' ([a]) es o bien una 'a' concatenada (:) en otra lista de 'a's', o bien una lista vacía ([]) data [ a ] = a : [ a ] | [] -- Algo de tipo Maybe a es o bien Just something, o bien Nothing data Maybe a = Just a | Nothing -- Algo de tipo Either atype btype es o bien un Left atype, o bien un Right btype data Either a b = Left a | Right bLos usuarios del lenguaje también pueden definir sus propios tipos de datos abstractos . Un ejemplo de un TDA utilizado para representar el nombre, el sexo y la edad de una persona podría ser:
datos Sexo = Masculino | Femenino datos Persona = Persona Cadena Sexo Entero -- Nótese que Persona es tanto un constructor como un tipo-- Un ejemplo de creación de algo de tipo Persona tom :: Persona tom = Persona "Tom" Masculino 27Sistema de tipos
- Clases de tipos
- Tipo predeterminado
- literales sobrecargados
- Polimorfismo de tipo superior
- Clases de tipos multiparámetro
- Dependencias funcionales
Mónadas y entrada/salida
- Descripción general del marco de la mónada :
- Aplicaciones
- E/S monádica
- notación de hacer
- Referencias
- Excepciones
mónada ST
La mónada ST permite escribir algoritmos de programación imperativa en Haskell, utilizando variables mutables (STRefs) y arreglos mutables (STArrays y STUArrays). La ventaja de la mónada ST radica en que permite escribir código con efectos secundarios internos, como la actualización destructiva de variables y arreglos mutables, manteniendo estos efectos dentro de la mónada. Como resultado, las funciones escritas con la mónada ST se comportan como código puro para el resto del programa. Esto permite utilizar código imperativo donde sería poco práctico escribir código funcional, conservando al mismo tiempo toda la seguridad que proporciona el código puro.
Aquí hay un programa de ejemplo (tomado de la página wiki de Haskell sobre la mónada ST ) que toma una lista de números y los suma, usando una variable mutable:
importar Control.Monad.ST importar Datos.STRef importar Control.MonadsumST :: Num a => [ a ] -> a sumST xs = runST $ do -- runST toma código ST con estado y lo convierte en puro. summed <- newSTRef 0 -- Crea un STRef (una variable mutable)forM_ xs $ \ x -> do -- Para cada elemento de la lista de argumentos xs .. modifySTRef summed ( + x ) -- agregarlo a lo que tenemos en n.readSTRef summed -- lee el valor de n, que será devuelto por runST arriba.mónada STM
La mónada STM es una implementación de la Memoria Transaccional de Software en Haskell. Está implementada en el compilador GHC y permite que las variables mutables se modifiquen en transacciones .
Flechas
- Funtores aplicativos
- Flechas
Como Haskell es un lenguaje puramente funcional, las funciones no pueden tener efectos secundarios. Al ser no estricto, tampoco tiene un orden de evaluación bien definido. Esto supone un reto para los programas reales, que, entre otras cosas, necesitan interactuar con un entorno. Haskell resuelve esto con tipos monádicos que aprovechan el sistema de tipos para garantizar la secuencia correcta de las construcciones imperativas. El ejemplo típico es la entrada/salida (E/S), pero las mónadas son útiles para muchos otros fines, como el estado mutable, la concurrencia y la memoria transaccional, el manejo de excepciones y la propagación de errores.
Haskell proporciona una sintaxis especial para expresiones monádicas, de modo que los programas con efectos secundarios se pueden escribir con un estilo similar al de los lenguajes de programación imperativos actuales; no se requieren conocimientos de las matemáticas que subyacen a la E/S monádica . El siguiente programa lee un nombre desde la línea de comandos y muestra un mensaje de saludo:
main = do putStrLn "¿Cuál es tu nombre?" name <- getLine putStr ( "Hola, " ++ name ++ "! \n " )La notación do facilita el trabajo con mónadas. Esta expresión do es equivalente a, pero (posiblemente) más fácil de escribir y comprender que, la versión simplificada que emplea directamente los operadores monádicos:
main = putStrLn "¿Cuál es tu nombre?" >> getLine >>= \ nombre -> putStr ( "Hola, " ++ nombre ++ "! \n " )- Véase también wikibooks:Transwiki:List of hello world programs#Haskell para otro ejemplo que imprime texto.
Concurrencia
La definición del lenguaje Haskell no incluye ni la concurrencia ni el paralelismo , aunque GHC admite ambos.
Concurrent Haskell es una extensión de Haskell que admite hilos y sincronización . [ 7 ] La implementación de Concurrent Haskell de GHC se basa en la multiplexación de hilos ligeros de Haskell en unos pocos hilos pesados del sistema operativo (SO), [ 8 ] de modo que los programas de Concurrent Haskell se ejecutan en paralelo mediante multiprocesamiento simétrico . El entorno de ejecución puede admitir millones de hilos simultáneos. [ 9 ]
La implementación de GHC emplea un grupo dinámico de subprocesos del sistema operativo, lo que permite que un subproceso de Haskell realice una llamada al sistema bloqueante sin bloquear a otros subprocesos de Haskell en ejecución. [ 10 ] Por lo tanto, los subprocesos ligeros de Haskell tienen las características de los subprocesos pesados del sistema operativo, y un programador puede desconocer los detalles de la implementación.
Recientemente, Concurrent Haskell se ha ampliado con soporte para memoria transaccional de software (STM), que es una abstracción de concurrencia en la que las operaciones compuestas sobre datos compartidos se realizan atómicamente, como transacciones. [ 11 ] La implementación de STM de GHC es la única implementación de STM hasta la fecha que proporciona una garantía estática en tiempo de compilación que impide que las operaciones no transaccionales se realicen dentro de una transacción. La biblioteca STM de Haskell también proporciona dos operaciones que no se encuentran en otras STM: y , que juntas permiten definir operaciones de bloqueo de forma modular y componible .retryorElse
Referencias
- ↑ HaskellWiki: Las firmas tipográficas como un buen estilo
- ↑ HaskellWiki: Pointfree
- ↑ "Números primos - HaskellWiki" . www.haskell.org .
- ↑ "Números primos - HaskellWiki" . www.haskell.org .
- ↑ O'Neill, Melissa E., "The Genuine Sieve of Eratosthenes" , Journal of Functional Programming , publicado en línea por Cambridge University Press el 9 de octubre de 2008, doi : 10.1017/S0956796808007004 , págs. 10, 11.
- ↑ "Números primos - HaskellWiki" . www.haskell.org .
- ↑ Simon Peyton Jones, Andrew Gordon y Sigbjorn Finne. Haskell concurrente . Simposio ACM SIGPLAN-SIGACT sobre principios de lenguajes de programación (PoPL). 1996. (Algunas secciones están desactualizadas con respecto a la implementación actual).
- ↑ Soporte en tiempo de ejecución para Haskell multinúcleo Archivado el 5 de julio de 2010 en Wayback Machine (Simon Marlow, Simon Peyton Jones, Satnam Singh) ICFP '09: Actas de la 14.ª conferencia internacional ACM SIGPLAN sobre programación funcional, Edimburgo, Escocia, agosto de 2009
- ↑ "DEFUN 2009: ¡Programación multinúcleo en Haskell ahora!" . 5 de septiembre de 2009.
- ↑ Ampliación de la interfaz de funciones externas de Haskell con concurrencia. Archivado el 3 de julio de 2010 en Wayback Machine (Simon Marlow, Simon Peyton Jones, Wolfgang Thaller). Actas del taller ACM SIGPLAN sobre Haskell, páginas 57-68, Snowbird, Utah, EE. UU., septiembre de 2004.
- ↑ Harris, Tim; Marlow, Simon ; Peyton Jones, Simon ; Herlihy, Maurice (2005). "Transacciones de memoria componibles". Actas del décimo simposio ACM SIGPLAN sobre principios y práctica de la programación paralela . CiteSeerX 10.1.1.67.3686 .
- Familia de lenguajes de programación Haskell