Haskell

De la Viquipèdia, l'enciclopèdia lliure
Per a altres significats, vegeu «Haskell (desambiguació)».
Infotaula de llenguatge de programacióHaskell
Tipusllenguatge de programació purament funcional, llenguatge de programació no estricte, llenguatge de programació modular, llenguatge interpretat, llenguatge de regles fora de joc, Llenguatge de programació compilat i llenguatge de programació Modifica el valor a Wikidata
Data de creació1990; fa 34 anys (1990)
DissenyLennart Augustsson, Warren Burton, Kevin Hammond, Paul Hudak, John Hughes, Thomas Johnsson, Simon Peyton Jones, John Launchbury, Erik Meijer, Alastair Reid (en) Tradueix i Philip Wadler Modifica el valor a Wikidata
DesenvolupadorPaul Hudak, Lennart Augustsson, John Hughes, Simon Peyton Jones, Erik Meijer i Philip Wadler Modifica el valor a Wikidata
EpònimHaskell Curry Modifica el valor a Wikidata
Paradigma de programacióprogramació funcional estandarditzat de semàntica no estricta i avaluació tardana
Darrera versió estableHaskell 2010[1]
Majors implementacionsGHC, Hugs, NHC, JHC, Yhc, UHC
DialectesHelium, Gofer
Influenciat perClean,[2] FP,[2] Gofer,[2] Hope and Hope+,[2] Id,[2] ISWIM,[2] KRC,[2] Lisp,[2] Miranda,[2] ML and ML Estàndard,[2] Orwell, SASL,[2] SISAL,[2] Scheme[2]
Ha influenciatAgda,[3] Bluespec,[4] C++11/Concepts,[5] C#/LINQ,[6][7][8][9] Cayenne,[6] Clean,[6] Clojure,[10] CoffeeScript,[11] Curry,[6] Escher,[12] F#,[13] Frege,[14] Hack,[15] Idris,[16] Isabelle,[6] Java/Generics,[6] LiveScript,[17] Mercury,[6] Perl 6,[18] Python,[6][19] Scala,[6][20] Swift,[21] Timber,[22] Visual Basic 9.0[6][7]
Sistema operatiumultiplataforma
Extensió dels fitxers.hs, .lhs
Etiqueta d'Stack ExchangeEtiqueta Modifica el valor a Wikidata
Pàgina webhaskell.org

Haskell és un llenguatge de programació funcional estandarditzat de semàntica no estricta i avaluació tardana de les expressions (ang: lazy evaluation) en el moment que se'n demana el valor i pren el nom del matemàtic Haskell Curry.

Es diu que és un llenguatge funcional pur. El cert és que admet variables d'estat però permet encapsular-ne els canvis (context ST), o bé circumscriure'n els efectes col·laterals al nivell superficial (context IO).

Haskell basa el polimorfisme en el requeriment d'implementació d'interfícies pels tipus dels paràmetres. Les interfícies amb un paràmetre de tipus t defineixen una partició de l'espai dels tipus en classes segons si les implementen o no, i per això s'anomenen classes de tipus.

-- classe de tipus (la interfície)
class Eq t where
 (==) :: t -> t -> Bool -- iguals
 (/=) :: t -> t -> Bool -- desiguals
 -- implementació per defecte
 x == y = not (x /= y)
 x /= y = not (x == y)
 -- caldrà especificar només una de les operacions en definir la implementació

data Bool = False | True -- definició del tipus Bool

-- instància (la implementació) de la classe Eq per al tipus Bool
instance Eq Bool where
 (==) False False = True
 (==) True True = True
 (==) _ _ = False

-- definició del tipus (Llista a) = Nil | Cons a (Llista a)
-- els símbols '[' i ']' designen una llista
data [a] = [] -- el constructor Nil es denota amb "[]"
 | a : [a] -- el constructor Cons es denota amb ':' en posició infix
-- * per sintaxi, si un símbol comença per ':', va infix
-- * tot identificador de funció es pot posar en infix si s'envolta de cometes revesses

-- exemple d'ús: "Eq t =>" es llegeix: per aquells tipus t tals que (Eq t)
ésMembre :: Eq t => t -> [t] -> Bool -- 
ésMembre x [] = False 
ésMembre x (cap : cua) = x == cap 
 || x `ésMembre` cua -- notació infix amb cometes revesses
  • les classes de tipus són com un mòdul genèric, amb el tipus com a paràmetre o índex, que defineix la signatura de les operacions on intervé el tipus indexat.[23]

Derivació automàtica d'instàncies (implementacions d'interfícies): També podem demanar al compilador que, per a classes de tipus bàsiques, derivi una instància partint de la representació interna del tipus (clàusula deriving en la definició de tipus estructurals (clàusula data).

data Color = Verd | Blau | Lila deriving (Eq, Show) -- el compilador deriva instàncies de les classes esmentades, obtenint la posició i el nom dels valors

Els literals no tenen tipus associat sinó que poden pertànyer a aquells tipus que implementin una determinada classe:

$ ghci -- a l'intèrpret
Prelude> :t 1
1 :: Num a => a -- 1 pot assignar-se a vars. d'aquells tipus que implementin la classe Num (que correspon a l'estructura algebraica d'anell)
Prelude> :t 1.5
1.5 :: Fractional a => a -- 1.5 pot assignar-se a vars. d'aquells tipus que implementin la classe Fractional (que correspon a l'estructura algebraica de cos)

-- la clàusula "default" permet l'assignació de tipus tradicional als literals, esmentant una seqüència de tipus a provar
default (Int, Double)

La sobrecàrrega de literals fa possible incorporar-los a diferents estructures:

{-# LANGUAGE OverloadedStrings, OverloadedLists #-}
import Data.Semigroup((<>))
import Data.Text (Text) -- text com a vectors de UTF-16
import Data.Set (Set)
import Data.Map (Map)

tiraDeText = ("abc" :: Text) <> "def" 
llista = ([1..3] :: [Int]) <> [4..6]
cjt = ([1..3] :: Set Int) <> [4..6]
dicc = ([(1,"a"), (2, "b")] :: Map Int String) <> [(3,"c")]

Tipus derivats: Corresponent a la derivació de classes de la P.O.O. Haskell possibilita la derivació de tipus amb la declaració newtype, heretant del tipus base les implementacions d'aquelles classes de tipus que esmentem a la clàusula deriving. Caldrà l'extensió de llenguatge GeneralizedNewtypeDeriving.[24]

Les implementacions no tenen nom. Un tipus no pot tenir diverses implementacions d'una classe de tipus, per ex. diverses ordenacions o diversos monoides per un mateix tipus. Caldrà crear-ne un tipus derivat amb newtype per cadascuna de les implementacions.

{-# LANGUAGE GeneralizedNewtypeDeriving #-} -- amplia les instàncies heretables del Haskell98

-- tipus derivat per implementar un Monoide per a la suma, parametritzat pel tipus base
newtype Sum a = Sum { getSum :: a }
 deriving (Eq, Ord, Read, Show, Bounded, Generic, Generic1, Num) -- classes de les instàncies a heretar
 -- el constructor obté, del tipus base, el tipus derivat
 -- l'accessor obté, del tipus derivat, el tipus base

instance Num a => Monoid (Sum a) where -- per aquells `a` que implementin Num (un anell algebraic)
 mempty = Sum 0 -- element neutre del Monoide
 Sum x `mappend` Sum y = Sum (x + y) -- operació associativa

Les col·leccions heterogènies d'altres llenguatges, aquí es tipifiquen per les operacions requerides, mitjançant tipus existencials (aquells tipus quins components implementin les classes de tipus requerides per al seu tractament).

{-# LANGUAGE ExistentialQuantification #-}

llistaHomo :: [Int]
llistaHomo = [1, 3, 4] -- llista homogènia

-- tipus "existencial": amb un component de tipus variable que compleixi una restricció
data ObjPresentable = forall a. (Show a) => Obj a -- per aquells tipus 'a' tals que "(Show a)"

presentaObj :: ObjPresentable -> String
presentaObj (Obj x) = "Obj " ++ show x 

-- llista d'elements amb components heterogenis, 
-- als quals podrem aplicar les operacions de les classes especificades a la restricció 
llistaHetero :: [ObjPresentable]
llistaHetero = [Obj 1, Obj "abc"]

El control de les operacions sobre els elements dels contenidors es pot fer de diverses maneres:

  • Mapeig: Si el contenidor implementa un Functor podrem estalviar múltiples recorreguts dels contenidors en aplicar diversos morfismes als elements, perquè per les lleis del Functor l'aplicació de la composició serà equivalent a la composició de les aplicacions individuals de cadascun dels morfismes. Els conjunts no són Functor
Si no hi ha efectes laterals
  • Els catamorfismes o plegaments són operacions que redueixen una col·lecció de valors a un de sol, altrament dit, una gramàtica A* -> A, a la classe Data.Foldable.[25]
  • Inversament, els anamorfismes[26] son operacions de desplegament que partint d'un valor anomenat llavor genera una col·lecció A -> A*. No tenen una classe específica. Es descriuen als mòduls de cada col·lecció.
  • Un Hylomorfisme és l'aplicació consecutiva d'un anamorfisme seguida d'un catamorfisme. Per exemple el càlcul del factorial desplega una seqüència de crides que és plegada en un valor final.
  • Un Metamorfisme és l'aplicació consecutiva d'un catamorfisme seguida d'un anamorfisme.
  • Un Paramorfisme és l'extensió del concepte de catamorfisme. Modela la recursió sobre un tipus de dades inductiu.
  • Un Apomorfisme és l'extensió del concepte d'anamorfisme, modelant la corecursió sobre un tipus coinductiu.
Quan hi ha efectes laterals cal controlar la seqüència de les operacions
la classe Traversable facilita l'avaluació seqüencial dels elements d'un contenidor d'accions o bé del mapeig dels elements amb una funció d'efectes.[27]
L'avaluació d'accions es pot fer de tres maneres possibles
  • Per combinació de resultats (les accions es podrien paral·lelitzar):
  • Els Functors aplicatius permeten combinar els resultats d'un seguit d'accions sense restringir-ne la temporalitat i componen les accions aplicant un resultat combinador de la primera, al resultat de l'acció següent. L'obtenció d'un resultat combinador es pot fer mitjançant l'aplicació d'un combinador de més d'un paràmetre, amb `fmap` a la primera acció, o també, elevant el combinador com a valor amb `pure` al tipus de l'efecte.
  • Per encadenament de resultats (serialització temporal):
  • Les Mònades componen les accions per encadenament del resultat doncs la segona acció pren forma de funció (amb efectes laterals) sobre el resultat de la precedent Hi ha una sintaxi específica (els blocs do) per descriure la composició de manera imperativa.
  • Les Fletxes generalitzen les funcions d'efectes laterals de les mònades, i componen les accions com un encadenament de resultats d'efectes funció d'una entrada que aplicarem a un valor inicial. Hi ha una sintaxi específica (els blocs proc) per descriure'n la composició.
Mònades amb efectes laterals funcionals
  • La mònada Reader possibilita l'encapsulament d'una funció d'un entorn que podem consultar (ask) i executar localment (amb local) una acció subordinada passant-li l'entorn modificat. L'entorn l'haurem de proporcionar inicialment en executar l'acció.[28]
  • La mònada Writer possibilita l'encapsulament d'una sortida incrementable com a Monoide que es pot consultar (listen), actualitzar (tell) i incrementar (censor).[29]
  • La mònada State possibilita l'encapsulament d'un estat que podrem consultar (get) i actualitzar (put).[30]
  • Els transformadors de mònades possibiliten l'encapsulament de la funcionalitat de diverses mònades.[31]
Programació genèrica

La programació genèrica, parametritzada per tipus, es concreta o bé

  • afegint paràmetres de tipus a les classes de tipus,
  • o bé, cas de tipus dependents, definint-los com a tipus associats a la classe
  • o bé mitjançant #Famílies de tipus (especificació a nivell global d'un tipus dependent quan es vol comú a diferents classes, per exemple el tipus de l'Element per a diferents classes de contenidors).

Haskell destaca en la facilitat per al paral·lelisme, per aprofitar la potència dels processadors multicor.[32][33]

A finals dels anys 1980 es va constituir un comitè amb l'objectiu de recollir en un llenguatge les característiques dels múltiples llenguatges funcionals de l'època, Miranda, ML i altres.

La primera versió va sortir el 1990. La versió més estesa actualment és la que correspon a l'informe Haskell 98.[34] Tanmateix el compilador GHC incorpora l'estàndard Haskell2010 per defecte a partir de la versió 7.0[35]

A principi de 2006 va començar el procés per definir-ne una nova revisió amb el nom de Haskell' ("Haskell prima", ang:"Haskell prime").[36] Diversos compiladors incorporen extensions del llenguatge que per a fer-les servir caldrà precedir el codi font amb la pragma {-# LANGUAGE extensió1, extensió2, ... #-} o bé el senyal corresp. de compilació (-Xextensió per al GHC). El wiki de "Haskell Prima" esmenta per cada extensió els compiladors que la implementen.[37]

Haskell 2010:[38] Actualment ha finalitzat el procés de discussió de les incorporacions a la nova versió de l'estàndard,[39][40] així com un nou procés d'evolució amb revisions (bi-)anuals del llenguatge.[41]

Propostes d'evolució del llenguatge aquí.[42]

Crítiques:

  • Haskell té un desavantatge important en la dificultat de depuració, que obliga a un esforç especial en la prevenció de fallades:
    • El model d'execució de Haskell fa que no hi hagi traça de pila de crides. Però se n'ha desenvolupat una de simulada per quan es compila per l'ajustatge (profiling). Per aquest cas, cal disposar de compilacions per l'ajustatge de totes les biblioteques relligades.[43][44][45]
    • Les petades per crides a error de les funcions parcials (proveu head []) donen, en compilació de producció, informació molt escassa: ni situació de l'error (a partir de GHC 8.0 error ja dona la posició, excepte al paquet base on s'ha mantingut la versió antiga, reanomenada errorWithoutStackTrace), ni la de la crida que incompleix la precondició. Per això es recomana no utilitzar-les en funcions parcials i convertir-les en totals amb resultat opcional caçant el cas no previst en l'anàlisi del retorn. Recentment des de GHC 7.10.2 hi ha la possibilitat d'obtenir el punt de crida d'origen mitjançant paràmetres implícits especials (Vegeu exemple). Alternativa més segura: evitar les funcions parcials (La biblioteca Safe ofereix alternatives a les funcions parcials predefinides del Prelude; el mòdul Data.List.NonEmpty ofereix llistes no buides com a tipus NonEmpty per aplicar de manera segura les funcions que petarien sobre llistes buides, per ex.: head).[46]
    • Els errors en funcions parcials de col·leccions no imprimeixen els valors causants, perquè la textualització dels elements (Show elem) no s'exigeix.
    • L'ús de traces per depurar es revela un maldecap per la irregularitat en l'ordre d'impressió que segueix l'ordre d'execució i no el d'especificació, indeterminat (per tant aleatori) en codi funcional pur, subjecte a l'avaluació tardana en traces en expressions let del codi monàdic (seqüencial).
    • El pas de paràmetres en les crides recursives (aval. tardana per defecte) pot fer petar la pila (pila d'avaluacions pendents) mentre no s'arriba al cas simple no-recursiu, si no s'avaluen de manera estricta els paràmetres acumuladors de manera completa, en profunditat (#Modes d'avaluació d'expressions i #Avaluació estricta explícita).
  • S'ha criticat que no hi hagi un sistema d'extensió de registres[47] i/o especialització. A l'intèrpret Hugs se'n va desenvolupar un anomenat TRex[48] (exemple) que GHC no ha incorporat.
  • En realitat es pot aconseguir facilitat en l'especialització de comportament, desacoblant la funcionalitat de l'estructura amb classes de propietats (getters/setters) com es descriu a l'Encapsulament estil O.O..
  • La implementació recent de polimorfisme de registres amb camps específics permet especificar els accessors com a requeriment de context, mitjançant la classe HasField (GHC 8.2), estalviant definir classes getters per aconseguir el polimorfisme (exemple verificat a #Polimorfisme de registres amb camps específics - la classe HasField).[49][50][51]
  • Les referències funcionals, anomenades lents, permeten l'actualització funcional d'estructures complexes en els seus components com un tot, reduint la necessitat de dividir la funció en els mòduls corresponents als components afectats com faríem a la POO.

Problemàtiques:

Vegeu secció #Problemàtiques.

Programa Hola Món[modifica]

El GHC (Compilador Haskell de Glasgow) és el compilador / intèrpret amb més possibilitats. Instruccions per obtenir-lo, les trobareu aquí.[52] o potser millor descarregant la Plataforma Haskell (La versió que incorpora la e./s. de caràcters no anglosaxons ja està disponible).

Per a Windows i altres podem descarregar-lo d'aquí.[52]

  • Una altra opció és descarregar el meta-gestor stack[53] que comprova el suport de biblioteques als rebostos #Stackage d'imatges de conjunts de versions compatibles de les biblioteques, i descarrega la versió més recent de GHC que s'hi ajusta, generant un fitxer stack.yaml amb les opcions escollides.
{-| fitxer hola-mon.hs
 * si no hi ha la clàusula ''module'', es pressuposa "module Main where"
-}
import Data.Function ((&)) -- importa l'operador (&): aplicació cap enrere
import Control.Category ((>>>)) -- importa l'op. composició d'esquerre a dreta

-- l'execució comença sempre per la funció inicial ''main'' del mòdul principal
-- alternatives:

main = putStrLn "Hola Món"

main = putStrLn $ "Hola" ++ " Món" -- ($) aplicació endavant, estalvia parèntesis

main = "Hola Món" & putStrLn -- (&) aplicació cap enrere 

main = ["Hola", "Món"] -- les claus designen una llista
 & unwords -- words separa paraules retornant-ne la llista, unwords és la inversa
 & putStrLn 

main = print 5
main = putStrLn . show $ 5 -- equivalent
main = show >>> putStrLn $ 5 -- equivalent
main = 5 & (show >>> putStrLn) -- equivalent

-- nota: 'print' converteix a String i imprimeix, equival a (putStrLn. show) 
-- show a una String li afegeix l'entrecomillat, amb 'print' una String acaba impresa amb duplicació de cometes.

En un sistema Linux podem tenir GHC i altres compiladors de Haskell i runhaskell es pot configurar per executar una alternativa o altra amb un selector d'alternatives de sistema[54] o bé amb la interfície gràfica galternatives[55] (normalment apunta a runghc). A MSWindows podem fer servir indistintament runhaskell o runghc.

Execució directa, sense generació d'executable, amb runhaskell[56]

$ runhaskell hola-mon # cerca el nom de fitxer amb l'extensió .hs (haskell source) o bé .lhs (literary haskell source)

Hola Món

Amb el meta-gestor stack:

# stack templates -- llista plantilles
# stack new projecte nom-de-plantilla
stack new projecte simple
cd projecte
# caldrà actualitzar el fitxer Main.hs al programa Hola-món
stack setup # configura, i descarrega el compilador
stack build # compila i relliga l'executable
stack exec projecte[.exe]

Amb l'intèrpret GHCi del mateix paquet, comanda ghci. Amb el meta-gestor escriuríem stack ghci.

A l'intèrpret no serveix la mateixa sintaxi del nivell declaratiu dels programes, sinó només la dels blocs "do" que permet especificar seqüencialment l'encadenament de resultats d'efectes mònadics; a banda de les comandes específiques[57] que comencen pel caràcter dos-punts i les expressions a avaluar.

Això canvia a partir de GHC 7.4.1 que admet tota mena de declaracions a l'intèrpret GHCi.[58]

$ ghci
GHCi, version 6.10.1: http://www.haskell.org/ghc/ :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer ... linking ... done.
Loading package base ... linking ... done.
Prelude> putStrLn "Hola Mon"
Hola Mon
Prelude> let str = "abc"
Prelude> :type str
str :: [Char]
Prelude> str
"abc"
Prelude> let f x y = x + y
Prelude> :type f
f :: Num a => a -> a -> a
Prelude>

Avaluador en-línia, a l'intèrpret d'expressions funcionals tryhaskell.org.

 reverse "Hola"
 > "aloH"
 :: [Char]

Cercadors de l'API[modifica]

  • Hayoo Arxivat 2010-03-22 a Wayback Machine. (servei interromput): on es podia consultar quines biblioteques exporten un identificador, a les biblioteques del rebost oficial (Hackage).
Permet cercar operadors no alfanumèrics com ara (>>=)
Disponible per a instal·lacions de cerca local[59]
  • Hoogle: permet, a més a més, cerca de funcions per signatura.[60] Exemples de cerca:
map
(a -> b) -> [a] -> [b]
Ord a => [a] -> [a]
Data.Map.insert
  • Hoogle5 permet alternatives de rebost (biblio estàndard, plataforma Haskell, el rebost Stackage) i cercar també en paquets específics, o bé per autor.

Característiques[modifica]

Afinant el rendiment[modifica]

Modes d'avaluació d'expressions[modifica]

En Forma Normal els valors estan avaluats completament.

Els termes Head Normal Form i Weak Head Normal Form són normalitzacions d'expressions del càlcul lambda.

En català està explicat al llibre pdf "Introducció a la programació funcional" de la Universitat de Girona.[61]

La definició del càlcul lambda segueix el document original d'Alonzo Church.

Terminologia del càlcul lambda (en notació Haskell):

  • E1 E2: aplicació de l'expressió E1 sobre el terme E2. L'aplicació és associativa per l'esquerra (E1 E2 E3) ≡ (E1 E2) E3
  • \ x -> E: abstracció lambda, quin cos pot contenir la variable lligada 'x' i altres de lliures. La var. lligada es refereix a l'argument de la lambda de var. coincident més pròxima que tapa el nom d'altres lambdes de nom coincident. L'abstracció lambda és associativa per la dreta.
(\ x -> \ y -> E)  (\ x -> (\ y -> E))

Cal tenir en compte que

(\ x -> M N)  (\ x -> (M N)) -- el cos de l'abstracció abasta el màxim cap a la dreta

(\ x y -> E)  (\ x -> \ y -> E) -- abreviació d'abstraccions
  • redex: contracció de l'anglès "reducible expression"
  • conversió alfa: es pot canviar el nom de la variable d'una abstracció lambda mentre el nom nou no coincideixi amb el de cap variable lliure del seu cos alterant-ne la condició.
  • beta-redex: expressió reduïble mitjançant una reducció beta.
  • eta-redex: expressió reduïble mitjançant una reducció eta.

reducció beta del càlcul lambda en notació Haskell[modifica]

Una expressió és beta-reduïble (beta-redex) si consisteix en l'aplicació d'una abstracció lambda (funció anònima d'una variable com a mínim) a un paràmetre. És de la forma

 (\ x -> E) P -- expressió "beta-reduïble"
-- la reducció 'beta' és la substitució de la variable 'x' pel paràmetre P en l'expressió E
-- el resultat ('reducte') en notació del càlcul lambda: E[x := P]
  • La notació d'índexs de De Bruijn evita el problema de col·lisió de noms en les substitucions. En comptes de noms les variables lligades es refereixen a l'argument per un índex d'aniuament de la variable respecte a l'abstracció lambda referida.
\ x -> \ y -> \ z -> x y z
-- amb notació de l'índex de De Bruijn seria
\ -> \ -> \ -> v3 v2 v1 -- la variable es refereix a l'argument per l'índex d'aniuament d'abstraccions

Una expressió beta reduïble està en posició de capçalera si és de la forma (en notació Haskell)

\ x1 x2 ... xi -> (\ y -> E) P1 P2 ... Pj -- l'expressió en capçalera és: (\ y -> E) P1 ... Pj

La seva reducció seria

\ x1 x2 ... xi -> E[y := P1] P2 ... Pj

reducció eta del càlcul lambda en notació Haskell[modifica]

Amb notació Haskell, de la definició del càlcul lambda.

Una abstracció lambda de la forma (\ x -> E x) és eta-reduïble (substituïble per E) si

  • la variable de l'abstracció coincideix amb el paràmetre més allunyat del cos,
  • i el nom de la variable (x) no pertany a les variables lliures de E.
-- reducció 'eta': l'expressió "eta-reduïble"
(\ x -> E x) 
-- és substituïble per 
E
-- sempre que 'x' no sigui una variable lliure de E
definició tàcita o point-free[modifica]

La programació tàcita o point-free (sense arguments) estalvia arguments en les definicions aplicant la reducció eta del càlcul lambda.

-- definició
arrelQuad x = sqrt x

-- en forma de lambda
arrelQuad = \x -> sqrt x 

-- per la reducció eta, atès que x no és una variable lliure de l'expressió (sqrt)
arrelQuad = sqrt -- versió tàcita o 'point-free' (estalviant arguments)

Head Normal Form[modifica]

Una expressió lambda està en "forma normal en capçalera" (HNF) si

  1. ja no té beta-redexs (expressions beta-reduïbles) en posició de capçalera, perquè s'han aplicat totes les reduccions beta possibles en aquesta posició (Forma normal beta).
  2. l'expressió en posició de capçalera no ha d'ésser tampoc una abstracció lambda amb el cos reduïble,[62] per què aquest cas es tipifica com a "forma normal dèbil en capçalera" (#Weak Head Normal Form).[63]

Weak Head Normal Form[modifica]

Vegeu [63] i[64]

Una expressió lambda amb el cos reduïble està en WHNF però no en HNF. El terme va ser encunyat per Simon Peyton Jones per explicitar la diferència entre HNF i el que la reducció de grafs fa a la pràctica: posposar la reducció del cos.[63]

Una expressió està en WHNF si està en HNF o bé és una expressió lambda amb el cos reduïble.[63]

Una expressió en WHNF està en una de les formes següents:[64]

  • Un Constructor, eventualment aplicat a expressions no reduïdes dels components
  • Una funció primitiva simple (d'implementació interna, ang: built-in, que no es basa en definicions) aplicada a menys paràmetres del que correspon a la seva aritat (per ex. "(+) 1" no es pot reduir mentre no disposem de tots els paràmetres que li manquen, doncs no hi ha cap definició de (+) on substituir els paràmetres insuficients)
  • Una abstracció lambda

Exemples de situacions d'avaluació a WHNF

  • evaluate de Control.Exception avalua com a efecte una expressió funcional llançadora d'excepcions, forçant l'avaluació a WHNF.
  • L'avaluació estricta de paràmetres quan es prefixen amb (!) els paràmetres formals (extensió BangPatterns) es fa a WHNF.

Forma Normal[modifica]

Una expressió està en forma normal si no s'hi poden aplicar més reduccions.[61] Està completament avaluada (en profunditat).

Una expressió que comença per un constructor està en HNF, i això impedeix l'avaluació de les expressions dels components (avaluant amb seq). Perquè quedin avaluades, cal, o bé definir-les estrictes als tipus, o bé avaluar amb deepseq o l'equivalent $!! a "forma normal".

La classe NFData (contracció de NormalFormData) del paquet deepseq[65] (a partir de GHC 7.4.1 forma part del conjunt bàsic de biblioteques de GHC) defineix la signatura d'una funció rnf (inicials de Reduce to Normal Form) per l'avaluació en profunditat. Per crear una instància de NFData per a un tipus algebraic, caldrà una implementació de rnf que apliqui recursivament rnf a les variables d'encaix corresponents als components dels constructors.

-- la funció ''rnf'' inicials de la traducció anglesa de "Reducció a Forma Normal"
class NFData a where
 rnf :: a -> () -- rnf ha d'avaluar el paràmetre en profunditat a Forma Normal
import Control.DeepSeq

data NomDelTipus = Cons1 T1 T2 | Cons2 T3

instance NFData NomDelTipus where
 rnf (Cons1 t1 t2) = (rnf t1) `seq` (rnf t2) `seq` ()
 rnf (Cons2 t3) = (rnf t3) `seq` ()

Automatitzable amb el travessament genèric de les estructures algebraiques.[66]

{-# LANGUAGE DeriveGeneric #-}

import Control.DeepSeq
import Control.DeepSeq.Generics (genericRnf)
import GHC.Generics

data NomDelTipus = Cons1 T1 T2 | Cons2 T3 deriving Generic

instance NFData NomDelTipus where rnf = genericRnf

Avaluació estricta explícita[modifica]

A part de l'optimització en estrictesa dels compiladors (vegeu article "Haskell és un llenguatge estricte")[67] es pot forçar l'avaluació estricta de les següents maneres:

Aplicació estricta (Crida per valor)[modifica]

Avaluació del paràmetre abans de la substitució (càlcul lambda). Amb l'operador d'aplicació estricta ($!) com a alternativa de ($) d'avaluació tardana. (seq) avalua el primer operand i retorna el segon. Al Haskell98 (seq) avaluava a HNF[68] però al Haskell2010 avalua a WHNF (posposa la reducció de les lambdes i de les expressions dels constructors).[69]

 f $! x = x `seq` (f x)

Aplicació estricta a Forma Normal[modifica]

($!!) amb doble signe d'exclamació, avalua l'operand en profunditat (amb deepseq) a Forma Normal, per als casos on l'operand és un tipus que implementa la classe NFData. La generació d'instàncies de NFData per a tipus algebraics es pot fer amb mecanismes de derivació genèrica (amb recorregut genèric dels tipus algebraics).

import Control.DeepSeq

-- ($!!) :: NFData a => (a -> b) -> a -> b -- infixr 0 $!!

f $!! x = x `deepseq` (f x)

Estrictesa als components dels tipus de dades[modifica]

data T = C T1 !T2 ... -- sense prefix al component => aval. tardana, amb (!) avaluació estricta

Quan en una definició de tipus de dades es prefixa el tipus del component amb '!' l'avaluació de l'aplicació del constructor a una expressió corresponent al component es fa amb ($!) i si no hi ha el prefix '!' es fa amb ($).[70]

Vegeu Eficiència i rendiment en tipus de dades[71]

  • La nova extensió de llenguatge StrictData de GHC 8.0 capgira el mode d'avaluació per defecte dels components, prefixant amb el caràcter titlla aquells que volguem d'avaluació tardana. Els newtype no queden afectats.[72][73]
{-# LANGUAGE StrictData #-} -- des de GHC 8.0
data T = C ~T1 T2 ... -- sense prefix al comp. => aval. estricta, amb (~) avaluació tardana

Estrictesa als paràmetres formals[modifica]

Avaluació estricta als paràmetres formals amb l'extensió {-# LANGUAGE BangPatterns #-}[72]

{-# LANGUAGE BangPatterns #-}
f !x !y = 2 * x * y -- avalua estrictament (!) els paràmetres actuals (a WHNF)

{-# LANGUAGE Strict #-} -- des de GHC 8.0
f x y = 2 * x * y -- amb Strict avaluació estricta no-irrefutable per defecte, prefix (~) per l'avaluació com abans

Estrictesa als patrons d'encaix[modifica]

Lligams amb avaluació estricta a les variables dels patrons

let !v = expr ... -- avalua estrictament l'expressió (amb (seq))
let (!x, !y) = (exprX, exprY) -- avalua estrict. les expr. de les variables del patró
  • La nova extensió de llenguatge Strict de GHC 8.0 capgira el mode d'avaluació per defecte d'un mòdul a estricte. Per obtenir l'avaluació tardana caldrà prefixar amb el caràcter titlla (~).[73]

foldl': iteracions amb plegat per l'esquerra estricte[modifica]

l'operació foldl (foldLeft) permet fer "transformacions reiterades sobre una estructura de tipus a amb els valors d'una seqüència [b] ((a -> b -> a)), de manera equivalent als bucles for|forEach de la prog. imperativa tradicional.

 foldl :: (a -> b -> a) -> a -> [b] -> a -- essent ''a'' l'estructura i ''[b]'' la llista de valors a iterar
-- versió tardana, cost O(n) en allotjament d'operacions pendents d'avaluar
foldl op estructInicial (x:xs) = foldl op (op estructInicial x) xs

-- versió estricta, avaluació primerenca
foldl' op estructInicial (x:xs) = let aplega_x = op estructInicial x
 in aplega_x `seq` foldl' op aplega_x xs
-- (seq) avalúa el primer operand i retorna el segon
-- si el tipus de ''aplega_x'' és algebraic (conté constructors (aturen l'avaluació)))

L'ús de tipus algebraics en l'operació, aturant l'avaluació en els constructors, implica la generació d'una pila de thunks (expressions pendents d'avaluar) que poden comportar el sobreiximent de la pila.

Treballar a espai constant de la pila[modifica]

El llibre RealWorldHaskell ofereix un exemple on l'operació nucli del plegat estricte foldl' plega sobre un parell, és a dir un tipus algebraic com a acumulador (constructor del parell amb les seves expressions).[74] Els constructors en posició de capçalera (vegeu #Head Normal Form) estan en HNF, per tant les expressions dels components no són avaluades. Això fa que s'amuntegui la seva avaluació pendent a la pila.

  • o bé s'avalua estrictament els components de l'acumulador compost dins l'operació del plegat
  • o bé es pot definir una versió de foldl'/foldr' que avaluï estrictament, però en profunditat a #Forma Normal.
import Control.DeepSeq (NFData, ($!!))
import Data.Foldable

-- de la definició de foldl' i foldr', substituint ($!) per ($!!) de DeepSeq per avaluar a Forma Normal

foldl'' :: (Foldable t, NFData b) => (b -> a -> b) -> b -> t a -> b
foldl'' f z0 xs = foldr f' id xs z0
 where f' x k z = k $!! f z x -- ($!) substituït per ($!!)

foldr'' :: (Foldable t, NFData b) => (a -> b -> b) -> b -> t a -> b
foldr'' f z0 xs = foldl f' id xs z0
 where f' k x z = k $!! f x z -- ($!) substituït per ($!!)

Estrictesa en les crides recursives[modifica]

Vegeu "Recursivitat final al Haskell".[75]

  • La "recursivitat final mòdulo cons" (recursivitat diferida) quan la crida recursiva és el component d'una dada que es retorna, no serà avaluada perquè els constructors de Tipus de dades algebraics aturen l'avaluació HNF.
duplicaLlista :: [a] -> [a]
duplicaLlista [] = []
duplicaLlista (x : xs) = x : duplicaLlista xs -- crida recursiva "mòdulo cons"
  • En cas de recursivitat final normal, el compilador optimitza alguns casos per evitar generar una pila d'expressions pendents d'avaluar (thunks)[76] però cal assegurar-se'n. Vegeu "Limitations of strictness analysis".[77]

Avaluació tardana explícita en els patrons d'encaix[modifica]

Els encaixos de patrons s'avaluen normalment de manera estricta (primerenca).[78]

» pattern matching is usually strict. So trying a pattern match forces evaluation to happen at least far enough to accept or reject the match.

Per avaluar un encaix de manera tardana (lazy) cal prefixar-lo amb el caràcter titlla '~'.[79]

L'avaluació tardana de l'encaix (vegeu exemple tot seguit) converteix l'encaix en irrefutable (no rebutjable, no parcial) evitant l'avaluació d'altres opcions.

L'ús de l'avaluació tardana explícita amb tipus amb més d'un constructor és perillós:[80]

f :: [a] -> [a]
f ~(x:xs) = x:xs
-- és traduït internament a
f ys = head ys : tail ys -- compte! funcions parcials!!
-- l'encaix (f ys), encaix amb variable, sempre té èxit.

-- si, per filtrar el cas [] no definit anteriorment, l'avaluem primer ...
f [] = []
f ~(x:xs) = x:xs -- l'avaluació tardana aquí és estúpida perquè l'encaix
 -- ja ha estat avaluat estrictament pel cas precedent []

-- si haguéssim posat el cas [] després: 
f ~(x:xs) = x:xs
f [] = []
-- el segon encaix (f []) no s'avalua mai, perquè l'anterior és irrefutable!
-- L'ordre és rellevant!!! El compilador ens avisarà del codi inabastable.

Programació de nivell baix[modifica]

Tipus primitius que es passen per valor (no encapsulats, ang:unboxed)[modifica]

Vegeu-ho a GHC

Tuples no encapsulades per al retorn de múltiples valors[modifica]

Vegeu-ho a GHC

Especialització d'operacions sobrecarregades[modifica]

Vegeu-ho a GHC

Referència ràpida de la biblioteca[modifica]

A GHC.

Haskell com a llenguatge Script[modifica]

Execució de Haskell com a Script a Unix (mitjançant una directiva Shebang).,[81] mitjançant l'eina stack:[82]

#!/usr/bin/env stack # directiva "Shebang" amb l'intèrpret seguit de paràmetres per a `stack script`
{- stack script
 --resolver lts-11.22 
 --package shelly -}

{-# LANGUAGE OverloadedStrings #-}

import Shelly (Sh, shelly, echo)

hola :: Sh ()
hola = echo "hola"

main :: IO ()
main = shelly $ hola

També admet mòduls externs posicionats segons la nomenclatura jeràrquica NomCarpeta.NomDeMòdul respecte del programa script.

Eines per les Comprovacions de Qualitat[modifica]

Proves unitàries
  • Biblioteca QuickCheck de comprovació de predicats sobre sèries de valors aleatoris amb acotació progressiva del domini del problema, mitjançant la instanciació de classes específiques (Arbitrary).[85][86]
  • Biblioteca HSpec inspirada per la biblioteca de Ruby RSpec.[87]
Verificació formal estàtica
  • La biblio. LiquidHaskell facilita la verificació formal estàtica mitjançant anotacions de "tipus refinats amb predicats" (ang: Logically Qualified Data Types) i un comprovador de lògica SMT (de l'anglès "Satisfiability modulo theories") determina si el programa és una solució d'una especificació teòrica formal que s'inclou.

Problemàtiques[modifica]

L'ús simultani de diferents biblioteques que utilitzin diferents versions d'una mateixa tercera biblioteca[88] comporta:

Un cop has generat l'executable, el següent maldecap són les petades de les funcions parcials, que criden a error per als valors per als quals no estan definides, (head []), sense cap pista del culpable:

Les crides recursives i els plegats poden generar piles d'expressions pendents d'avaluar, fent petar la pila, si no s'explicita correctament l'avaluació estricta dels acumuladors i dels components de les estructures intermèdies:

La modificació de l'estat global (preferències) en temps d'execució dona lloc al:

Perquè la imatge en memòria del programa no creixi més del compte cal tenir en compte:

Gestor de projectes i empaquetatge de biblioteques i aplicacions[modifica]

El Haskell utilitza un gestor de projectes per resoldre les dependències d'altres biblioteques i facilitar-ne la compilació on s'instal·len, amb independència del compilador emprat.

Aquest gestor es diu Cabal[89][90] (Common Architecture for Building Applications and Libraries)[91] i utilitza arxius de descripció de projecte amb l'extensió ".cabal". Vegeu "Com crear un paquet executable o bé biblioteca"[92][93]

El nom del paquet consta de nom-versió, per ex. shakespeare-css-1.0.1.2, on la versió major són els dos primers components numèrics (un canvi en la versió major indica trencament de compatibilitat amb l'API anterior), la versió menor és el tercer (identifica la API, un canvi significa un augment de l'API sense trencament)), i el quart indica modificacions sense variar l'API.[94]

Els paquets es descarreguen en directoris dins del $HOME/.cabal, els executables de les aplicacions quedaran a $HOME/.cabal/bin que caldrà afegir a la variable d'entorn PATH.

Els paquets ja instal·lats per GHC es gestionen amb el programa ghc-pkg.

Al Linux podem començar treballant amb les biblioteques precompilades en paquets de la distribució de Linux. Si us cal una versió més recent del compilador, caldrà instal·lar-lo prèviament i, en acabat, instal·lar #The Haskell Platform, contràriament al Windows on el paquet #The Haskell Platform l'incorpora.

El rebost oficial de biblioteques i aplicacions és el Hackage[95]

  • instal·lació manual: Si no es disposa de l'executable cabal del paquet cabal-install, per instal·lar un paquet cal descarregar-lo, buscar el fitxer Setup.hs o bé Setup.lhs i executar
 runhaskell Setup clean # neteja arxius producte de compilacions anteriors
 runhaskell Setup configure —help # mostra opcions generals i específiques del paquet
 runhaskell Setup configure —user —altres-opcions
 runhaskell Setup build
 [sudo] runhaskell Setup install # ''sudo'' (privilegi d'admin. del sistema) si configures amb —global en comptes de —user
 #, per actualitzar el rebost del sistema
  • instal·lació automatitzada d'un paquet del rebost Hackage:

Amb "cabal" descarrega, configura, compila i instal·la d'una sola tacada, després d'instal·lar automàticament els paquets dels quals depèn. Preguntes freqüents aquí.[96]

 # l'ajuda és per comanda
 cabal help install
 # --with-compiler=... permet seleccionar el compilador
 # <versió> = <digit> {'.' <digit>} ['.' '*']
 # <paquet_o_dependència> :== nom | nom-versió | "nom < versió" | "nom == versió"
 cabal install paquet1 paquet2 --opcions
  • per llistar els paquets que ja tenim a GHC, "ghc-pkg list". No existeix encara l'equivalent "hugs-pkg"[97]
  • en cas de problemes per biblioteques que no compilen bé, és útil limitar-ne la versió amb l'opció—constraint=dependència
# restricció de dependències en compilar
--constraint="nom_biblio < versió" 
# o bé 
--constraint=nom_biblio==versió # (Els 3 primers components de la versió identifiquen l'API)

# exemples (les cometes només fan falta si hi ha espais o bé
# si l'operador de comparació conté símbols '<' '>' de l'intèrpret de comandes per a la redirecció):
cabal install QuickCheck --constraint=BiblioDeLaQualDepen==2.3.4.*
  • a partir de cabal-install v.1.16 cabal admet paral·lelisme en la instal·lació (opció -j)
cabal install -j "wx == 0.13.*"

Conflictes de dependències[modifica]

Tanmateix cal tenir en compte que l'ús simultani de biblioteques que facin servir diferents versions d'un mateix paquet és molt problemàtic.[98] Cal evitar absolutament la comanda cabal upgrade que ens abocaria al problema esmentat.[98]

Entorn aïllat de desenvolupament amb cabal sandbox[modifica]

cabal amb el verb sandbox[99] crea un dipòsit de biblioteques específic del projecte en el subdirectori amagat ".cabal-sandbox". Una sandbox (capsa de sorra literalment) és un entorn tancat per a proves per evitar que els errors que s'hi produeixin repercuteixin a l'exterior. Aquesta funcionalitat es va desenvolupar al programa cabal-dev[100] que ara ha quedat obsolet.

  • els executables queden al directori ./.cabal-sandbox/bin que caldrà afegir a la var. d'entorn d'executables PATH.
  • s'hi poden associar subprojectes amb la comanda
cabal sandbox add-sources camí/al/subprojecte

Per a més info. consulteu cabal sandbox --help.

  • Aquesta funcionalitat ha quedat superada pel meta-gestor stack que allotja les dependències locals (definides al projecte.cabal) en una capsa-de proves "./.stack-work" i les globals en subcarpetes d'usuari "~./stack" per versions, evitant recompilar-les per cada projecte.

El rebost Stackage - rebost alternatiu amb dependències verificades[modifica]

Stackage[101] proporciona imatges de conjunts de biblioteques amb compatibilitat verificada de versions, entre elles i una versió específica de GHC, amb noves imatges dels rebostos a mesura que sorgeixen noves versions de dependències o del compilador.

Vegeu Compilador Haskell de Glasgow#Stackage - rebost alternatiu amb dependències verificades

Creació del fitxer de projecte .cabal[modifica]

cabal init
interroga l'usuari a la cònsola de comandes i genera un esquelet de projecte que caldrà editar posteriorment per afegir-hi els noms dels fonts i els paquets dels quals depèn. Caldrà afegir-hi manualment la llista de mòduls exportats si és una biblioteca (secció exposed-modules), dels mòduls no exportats (secció other-modules) i de les dependències (secció build-depends).
  • superat pel sistema de plantilles de stack: stack new projecte plantilla
leksah
Entorn gràfic d'usuari (IDE) que conté un formulari d'edició del fitxer de projecte.

Un cop creat, la comanda cabal sense nom de paquet treballa sobre el fitxer de projecte del directori de treball:

cabal sandbox init # genera un rebost de biblioteques específic del projecte
 # els executables quedaran a la carpeta ".cabal-sandbox/bin"
cabal sandbox add-sources camí/al/subprojecte # afegir subprojecte
cabal sandbox delete # elimina el rebost específic

cabal clean # neteja tots els fitxers generats per la compilació
cabal configure # estableix opcions i comprova compatibilitat de les dependències
cabal build # compila
cabal install # configura, compila, relliga i instal·la
cabal freeze # fixa les versions de les dependències com a restricció
 # al fitxer "cabal.config" de restriccions a la carpeta del projecte
cabal repl # engega l'intèrpret 'ghci' havent carregat mòduls i opcions esmentades al fitxer de projecte

Vegeu també "Com escriure (i empaquetar) un programa en Haskell".[102] També "Actualitzant un paquet a noves versions de GHC i biblioteques".[103]

Gestió dels paquets instal·lats[modifica]

Amb ghc-pkg comprova paquets instal·lats a les BDD de paquets de l'usuari i del sistema.[104]

$ ghc-pkg list 

$ ghc-pkg check # comprova dependències trencades per la reinstal·lació d'aquestes

En un entorn de desenvolupament aïllat en capsa-de-proves (sandbox):

cabal sandbox hc-pkg ...

Instal·lació des del GitHub[modifica]

L'aplicació cabalg descarrega (amb git-clone a subcarpeta) i instal·la (amb cabal).[105]

cabalg https://github.com/usuari/projecte-github # descarrega a subcarpeta de nom "projecte-github"

Stack - Meta-gestor de projectes[modifica]

L'aplicació Stack[106][107][108][109] sobreposa la seva operativa a la del gestor cabal millorant-la en diversos aspectes:

  • proporciona plantilles per a diversos tipus d'aplicacions
  • utilitza els rebostos Stackage[110] de dependències de compilació verificada amb versions específiques de GHC
  • cerca automàticament el rebost Stackage més recent que contingui les dependències (biblioteques) esmentades al fitxer .cabal del projecte
  • descarrega la versió de GHC corresponent al rebost, si encara no ho ha fet
  • millora el rendiment del desenvolupament aïllat en "Sandbox" (Capsa de proves): la Sandbox (a la carpeta ./.stack-work) només guarda les biblioteques definides localment, al fitxer de projecte .cabal, mentre que les dependències es compilen un sol cop per a diversos projectes, guardant dins la carpeta d'usuari (~/.stack) les compilacions de dependències requerides segons la versió d'origen del rebost.
stack templates # llista les plantilles de fonts per a nous projectes
stack new projecte <template> # genera un projecte nou (amb fonts i projecte.cabal) partint d'una plantilla
#
cd projecte
stack setup # cerca la versió de Stackage que contingui les dependències del projecte, i descarrega el compilador GHC corresponent.
stack build # compila i instal·la -- les dependències a (~/.stack), i els paquets locals del projecte a (./.stack-work)
# l'executable queda a .stack-work/install/<arquitectura>-<sist_op>/<versió_de_stackage>/<versió_de_ghc>/bin
stack exec projecte # nom de l'executable al fitxer de projecte .cabal (pot variar amb sufixos o extensions)
  • les dependències (biblioteques) que no siguin al rebost stackage però sí al hackage cal esmentar-les a l'apartat extra-deps de stack.yaml.
  • les dependències personalitzades per al projecte, cal allotjar-les en un subdirectori del projecte, esmentar-les a l'apartat packages de stack.yaml i instal·lar-les mitjançant el subdirectori.
stack install local-pkgs/el-meu-paquet-personalitzat/

Política de versions[modifica]

Vegeu ref.[111]

Els paquets s'identifiquen amb un número de versió amb dígits separats per un punt, amb un mínim de tres components A.B.C on A.B s'anomena versió major i C la versió menor.

  • Cal incrementar el nombre de versió major A.B en cas de modificació de l'API quan:
  • l'actualització elimina alguna entitat
  • o bé s'han modificat tipus, entitats, definicions d'estructures (data), o classes
  • o bé s'han afegit instàncies òrfenes (les que no acompanyen les definicions ni de la classe ni del tipus)
  • o bé s'han eliminat instàncies de classes
  • Cal incrementar la versió menor C en cas d'increment de l'API quan:
  • s'afegeixen noves definicions, tipus, classes, instàncies no òrfenes i mòduls.

Eines relacionades amb el gestor de projectes[modifica]

cabal-progdeps
[112] llista les dependències en un directori de projecte
yackage
[113] servidor de rebost "hackage" local per a desenvolupament

The Haskell Platform[modifica]

The Haskell Platform vol ser un instal·lador empaquetant el compilador GHC (només a Windows, a Unix i derivats cal descarregar-lo prèviament), una biblioteca i un paquet d'eines incorporant paquets de rutines[114] del rebost Hackage.[95] amb encaix verificat respecte a la versió de la biblioteca Base[115] inclosa. (Preguntes freqüents)[116]

Backpack - Abstracció de biblioteques[modifica]

Backpack[117][118][119] (cat: Motxilla) permet substituir una dependència directa d'un paquet en una funció, tipus o paquet per una o més signatures. El desenvolupador adjunta un mòdul d'interfície abstracta de requeriments (clàusula Signature) i l'usuari decideix el paquet d'implementació que hi relligarà.

Backpack evita haver de mantenir diverses versions d'una mateixa biblioteca que facin servir tipus definits externament lleugerament diferents però amb la mateixa interfície (per exemple diferents tipus de cadenes: Data.ByteString.Lazy i Data.ByteString.Strict o també diferents implementacions d'un servei) i haver de relligar-les totes si se'n vol disposar.[120]

Per evitar les múltiples versions del codi, Backpack emula els mòduls paramètrics functors de ML Estàndard, però amb l'estil de mix-in imitant el sistema de mòduls de MixML.[121][122]

Caldrà que el codi client faci referència al tipus definit abstracte en un mòdul d'interfície (nova clàusula Signature) que descriurà la funcionalitat requerida, i que empaquetarem en un paquet functor.

Després, podrem fer-ne ús directament o també, generar paquets instàncies del functor, i donar nom específic als aparellaments de mòdul client de la signatura amb el mòdul que la implementa (clàusula "mixins" de Cabal, o bé clàusula "dependency" en el nou format .bkp).[120][123]

Backpack requereix GHC >=8.2 i Cabal >=2.0.[123]

Per a l'ús de Backpack amb el format tradicional de paquets i en paquets multi-biblioteca vegeu la ref.[124] L'extensió dels fitxers de Signatura haurà de ser ".hsig"

Mentre Stack no suporti Backpack, es pot fer servir de moment mitjançant les "capses de prova Sandbox" cabal sandbox, fins i tot amb rebostos Stackage especificant el rebost desitjat ("remote-repo") en un fitxer de configuració local "cabal.config"

La versió de GHC per a la Màquina virtual Java anomenada "Eta" també suporta Backpack.[125]

nou format

GHC suporta un format nou amb extensió (.bkp) de codi font amb múltiples clàusules unit com a unitat de compilació equivalent a biblioteques, que engloba diversos mòduls habituals d'implementació i mòduls d'interfície per la clàusula signature.[123] Vegeu exemple.

{-| fitxer hello.bkp -}
unit main where -- unitat de compilació
 module Main where
 main = putStrLn "Hello world!"
# per compilar (GHC >= 8.1.20161007)
 ghc --backpack hello.bkp
# genera subcarpeta de compilats amb el nom de la unitat de compilació
# executable a ./<unit>/Main
exemple de paquet functor (en el sentit de ML_Estàndard)
Mòdul abstracte funció d'una signatura adjunta (motxilla). Permet definir mòduls concrets (al fitxer de projecte) per l'aplicació del mòdul functor a un mòdul que implementi la signatura, aportat per un altre paquet.[123]
-- paquet functor
unit regex-indef where -- unitat de compilació 

 signature Str where -- interfície "motxilla" abstracta de requeriments 
 -- que haurà d'implementar un mòdul d'un paquet extern,
 data Str
 instance Eq Str
 null :: Str -> Bool
 singleton :: Char -> Str
 splits :: Str -> [(Str, Str)]
 parts :: Str -> [[Str]]

 module Regex where -- mòdul client
 import Str -- importa l'espai de noms de la interfície "motxilla"
 ...

Entorns de desenvolupament i altres eines[modifica]

hlint
Aquí[126] analitzador de codi amb suggeriments de millora. Avisa de construccions redundants i proposa alternatives al codi.
Leksah
Aquí.[127] Entorn gràfic de desenvolupament (IDE) basat en GTK, útil per estudiar un paquet. Genera fitxers de projecte en format .cabal. Permet obtenir info. a partir del menú de context, dels elements que marqueu d'un programa. Instruccions d'instal·lació aquí[128] Permet la depuració de programes (Truc: cal definir-hi un Workspace i un Package perquè s'activi la depuració).
eclipseFP
Aquí.[129] Endollable per a l'entorn de desenvolupament (IDE) Eclipse
Visual Haskell 2005
Entorn de Microsoft Visual Studio per al Haskell. Hi va haver un desenvolupament per al Visual Studio 2005 inacabat segons les fonts.[130] Malgrat que el compilador GHC el desenvolupa Microsoft Research a Cambridge (Regne Unit), no hi ha eines de suport específiques del Microsoft Windows.
ThreadScope
Analitzador de paral·lelisme al GHC. Vegeu GHC#Eines.
hpc (haskell program coverage)
Anàlisi de cobertura del codi. Genera traces d'execució i, després de diverses execucions, permet mostrar en un informe html, amb marcatge de colors, quines parts del codi no s'han executat mai i quines expressions booleanes són sempre certes o sempre falses. Vegeu GHC#Eines.
hp2any
perfil d'ús de memòria en temps real i diferit. Vegeu GHC#Eines.
hgettext
eina que permet extreure cadenes de text del codi font per preparar la internacionalització amb traduccions múltiples.[131]

Implementacions[modifica]

Vegeu[132]

GHC ("Glasgow Haskell Compilation System")
Compilador[133] i intèrpret (GHCi)[134] que va més enllà del Haskell98.

Incorpora "concurrència","[135]paral·lelisme","[136]Memoria Transaccional per Software"[137][138] i opcions d'optimització. Pot generar codi nadiu, codi C, o codi optimitzat mitjançant LLVM.[139]

A partir de la versió 6.10 incorpora "Data Parallel Haskell"[140][141] per al tractament paral·lel de vectors.

L'intèrpret ghci genera codi intermedi i admet l'execució mixta de codi intermedi i codi nadiu.

Hugs
Intèrpret.[142] Implementació quasi completa del Haskell 98. Incorpora registres extensibles anomenats TRex.[143]
nhc98
Compilador[144] per a màquines de 32 bits. Intèrpret "Hi". Muntador "Hmake".
UHC / EHC
Utrecht Haskell Compiler / Essential Haskell Compiler[145] amb rerefons de compilació per a llenguatge C, Java, LLVM i CLR.[146]
YHC
York Haskell Compiler[147] amb rerefons de compilació a Javascript[148] i traçador de crides Hat[149]
JHC
Jhc Haskell Compiler[150] Compilador de John Meacham.[151]
LHC
LHC Haskell Compiler[152] Projecte derivat del JHC.

Extensions de noms de fitxer[modifica]

Vegeu enllaç[153]

.hs
Haskell source
.lhs (Literate haskell source)
font documentat segons Programació literària immergint el codi dins la documentació:
.cabal
descripció de paquet Cabal
.x
doc. de lèxic, entrada per al generador d'analitzadors de lèxic Alex (de l'estil del lex al Unix) (genera *.hs)
.lx
doc. de lèxic Alex literari (a l'estil del .lhs)
.y
doc. de gramàtica, per al generador d'analitzadors gramaticals Happy (de l'estil del yacc al Unix) (genera *.hs)
.ly
doc. de gramàtica Happy literari (a l'estil del .lhs)
.gc
doc. d'entrada al GreenCard (descripció enllaç amb codi C) adaptat al FFI (Foreign Function Interface) normatiu per a Haskell2010[39]
.chs
doc. d'entrada al convertidor c2hs
.hsc
doc. d'entrada al convertidor hsc2hs

Plataformes, aspectes[modifica]

plataformes virtuals[modifica]

sobre Xen

rerefons de compilació[modifica]

via LLVM (Low Level Virtual Machine)
  • GHC pot compilar via LLVM per aprofitar-ne les optimitzacions específiques per arquitectura del processador.[157] Comproveu-hi les "Plataformes suportades"[158]
amb sortida JVM
  • Eta (eta-lang.org): rerefons JVM per a GHC amb ampliació de sintaxi per la definició de la interfície d'importació/exportació a Java
  • vegeu "Haskell on Android using Eta".[159]
  • UHC Jazy: Rerefons JVM per al compilador UHC. (implementació parcial).[160]
amb sortida JavaScript
  • Haste: modificació de GHC amb rerefons JavaScript.[161]
  • GhcJs: modificació de GHC amb rerefons JavaScript.[162]
  • Yrc2Js: Rerefons a Javascript del compilador YHC (Compilador Haskell de York).[163]
  • UHC: Rerefons (en desenvolupament) de l'"Utrecht Haskell Compiler"[164]
  • Elm: llenguatge per a interfícies Web d'arquitectura MVC amb sintaxi quasi Haskell, que compila a Javascript, per a la composició d'interfícies gràfiques sobre navegadors web.
  • PureScript: llenguatge quasi Haskell d'avaluació estricta amb sortida JavaScript.[165]
amb sortida CLR

Altres plataformes[modifica]

A sistemes d'Apple (Mac OS, iOS)

Dialectes del Haskell[modifica]

DDC (The Disciplined Disciple Compiler)
(cat: El Compilador del Deixeble Disciplinat): versió d'avaluació estricta, contràriament a Haskell (en desenvolupament).[168]
OOHaskell
biblioteca d'orientació a objectes d'Oleg Kyseliov i Ralf Lämmel (versió del 2005 no actualitzada).[169]
O'Haskell
versió orientada a objectes[170] de Johan Nordlander. Treball del 2001 evolucionat a Timber
Timber
evolució de O'Haskell, per a la programació reactiva de sistemes encastats.[171] (del mateix autor Johan Nordlander). Limitacions i problemàtiques[172]
Hume
llenguatge funcional estricte (avaluació primerenca) per a sistemes encastats de recursos limitats, amb concurrència per pas de missatges i característiques CSP on la sintaxi del nivell d'expressions és la del Haskell.
Incorpora limitació de costos de recursos per procés, en temps, memòria dinàmica i mida de la pila amb les corresponents excepcions.
CAL
aproximació a Haskell sobre la JVM integrat dins Open Quark de Business Objects,[173][174] companyia francesa absorbida pel gegant alemany del programari SAP AG
Jaskell
llenguatge sobre la Màquina virtual Java, funcional i d'avaluació tardana, força diferent en sintaxi.[175]
Frege
llenguatge quasi Haskell d'avaluació tardana sobre la JVM, amb particularitats del Java (literals Java, mètodes als tipus de dades, ...) sobre Java-7[176]
Eta
eta-lang.org Compilador de Haskell estàndard (GHC) ampliat amb elements d'orientació a objectes, sortida a JVM i interoperativitat FFI amb Java.
Elm
llenguatge quasi Haskell estricte (avaluació primerenca), d'arquitectura MVC per generar interfícies gràfiques a la web, compilant a JavaScript (no admet definició de signatures de tipus, excepte algunes de predefinides anomenades categories).
Idris
llenguatge estricte (avaluació primerenca) amb sintaxi quasi haskell amb tipus dependents de valors i tipus com a objectes de primer ordre. Incorpora mecanismes de certificació estàtica, com els llenguatges anomenats "comprovadors de teoremes" per ex.: Coq i Agda.
PureScript
llenguatge quasi Haskell estricte (avaluació primerenca) per compilar a JavaScript en mòduls de Node.js, amb tipus bàsics Javascript, i construccions esbiaixades cap al JavaScript, per exemple les claus rectangulars no indiquen llista sinó el tipus Array.[165]
DAML
daml.com llenguatge per l'especificació de contractes, basat en una modificació de GHC.

Exemples[modifica]

Vegeu Característiques del llenguatge Haskell#Exemples

Referències[modifica]

  1. Marlow, Simon. «Announcing Haskell 2010», 24-11-2009. [Consulta: 12 març 2011].
  2. 2,00 2,01 2,02 2,03 2,04 2,05 2,06 2,07 2,08 2,09 2,10 2,11 2,12 Peyton Jones 2003, p. xi
  3. Norell, Ulf. «Dependently Typed Programming in Agda». Gothenburg: Chalmers University, 2008. [Consulta: 9 febrer 2012].
  4. Hudak et al., 2007, p. 12-38,43.
  5. Stroustrup, Bjarne; Sutton, Andrew. Design of Concept Libraries for C++, 2011.  «Còpia arxivada». Arxivat de l'original el 2012-02-10. [Consulta: 13 novembre 2015].
  6. 6,00 6,01 6,02 6,03 6,04 6,05 6,06 6,07 6,08 6,09 Hudak et al., 2007, p. 12-45–46.
  7. 7,0 7,1 Meijer, Erik «Confessions of a Used Programming Language Salesman: Getting the Masses Hooked on Haskell». OOPSLA 2007.
  8. Meijer, Erik. «C9 Lectures: Dr. Erik Meijer – Functional Programming Fundamentals, Chapter 1 of 13». Channel 9. Microsoft, 01-10-2009. Arxivat de l'original el 16 de juny 2012. [Consulta: 9 febrer 2012].
  9. Drobi, Sadek «Erik Meijer on LINQ». InfoQ. C4Media Inc. [QCon SF 2008], 04-03-2009 [Consulta: 9 febrer 2012].
  10. Hickey, Rich. «Clojure Bookshelf». Listmania!. Amazon.com. [Consulta: 9 febrer 2012].
  11. Heller, Martin «Turn up your nose at Dart and smell the CoffeeScript». JavaWorld. InfoWorld, 18-10-2011 [Consulta: 9 febrer 2012]. Arxivat 10 de febrer 2012 a Wayback Machine. «Còpia arxivada». Arxivat de l'original el 2012-02-10. [Consulta: 13 novembre 2015].
  12. «Declarative programming in Escher». [Consulta: 7 octubre 2015].
  13. Syme, Don; Granicz, Adam; Cisternino, Antonio. Expert F#. Apress, 2007, p. 2. «F# also draws from Haskell particularly with regard to two advanced language features called sequence expressions and workflows 
  14. Wechsung, Ingo. «The Frege Programming Language». [Consulta: 26 febrer 2014].
  15. [enllaç sense format] http://www.wired.com/2014/03/facebook-hack/
  16. «Idris, a dependently typed language». [Consulta: 26 octubre 2014].
  17. «LiveScript Inspiration». [Consulta: 4 febrer 2014].
  18. «Glossary of Terms and Jargon». Perl Foundation Perl 6 Wiki. The Perl Foundation, 28 February. Arxivat de l'original el 21 de gener 2012. [Consulta: 9 febrer 2012].
  19. Kuchling, A. M. «Functional Programming HOWTO». Python v2.7.2 documentation. Python Software Foundation. [Consulta: 9 febrer 2012].
  20. Fogus, Michael. «MartinOdersky take(5) toList». Send More Paramedics, 06-08-2010. [Consulta: 9 febrer 2012].
  21. Lattner, Chris. «Chris Lattner's Homepage». Chris Lattner, 03-06-2014. [Consulta: 3 juny 2014]. «The Swift language is the product of tireless effort from a team of language experts, documentation gurus, compiler optimization ninjas, and an incredibly important internal dogfooding group who provided feedback to help refine and battle-test ideas. Of course, it also greatly benefited from the experiences hard-won by many other languages in the field, drawing ideas from Objective-C, Rust, Haskell, Ruby, Python, C#, CLU, and far too many others to list.»
  22. «Timber/History». [Consulta: 7 octubre 2015].
  23. HaskellWiki - Polimorfisme(anglès)
  24. GHC Users guide - GeneralizedNewtypeDeriving Arxivat 2018-08-21 a Wayback Machine.(anglès)
  25. La classe Foldable(anglès)
  26. Erik Meijer et al. - Functional programming with Bananas, Lenses, Envelopes and Barbed Wire(anglès)
  27. La classe Traversable(anglès)
  28. La mònada Reader(anglès)
  29. La mònada Writer(anglès)
  30. La mònada State(anglès)
  31. Monad transformers(anglès)
  32. [Parallel Haskell: Projecte de dos anys per promocionar-ne l'ús en el món real](anglès)
  33. Haskell - Concurrència i paral·lelisme(anglès)
  34. Haskell98 Online Report(anglès)
  35. GHC - Notes de l'edició(anglès) GHC 7.0+ pren per defecte l'estàndard de llenguatge Haskell2010
  36. Haskell prima - Propostes per a l'evolució del llenguatge Arxivat 2016-02-20 a Wayback Machine. (anglès)
  37. Extensions del Haskell i compiladors que les implementen Arxivat 2019-12-21 a Wayback Machine.(anglès)
  38. Haskell2010 Online Report(anglès)
  39. 39,0 39,1 Anunciant Haskell 2010(anglès) Acord final sobre Haskell 2010
  40. Característiques del Haskell 2010 Arxivat 2009-11-30 a Wayback Machine. (anglès)
  41. Anunci del nou procés Haskell Prima, i del Haskell 2010 (anglès)
  42. Propostes per a Haskell 201x Arxivat 2018-01-25 a Wayback Machine.(anglès)
  43. Haskell wiki - Depuració(anglès)
  44. HaskellWiki - Stack Overflow(anglès)
  45. Simon Marlow - Why can't I get a Stack trace(anglès)
  46. El paquet safe(anglès)
  47. Extensible Records(anglès)
  48. «Extensió TRex de l'intèrpret Hugs». Arxivat de l'original el 2012-03-20. [Consulta: 12 març 2012].
  49. Well-typed - Polymorphism over record fields(anglès)
  50. OverloadedRecordFields(anglès)
  51. Implement HasField constraint solving and modify OverloadedLabels Arxivat 2018-01-25 a Wayback Machine.(anglès)
  52. 52,0 52,1 Obtenir el compilador GHC
  53. Haskell Stack(anglès)
  54. Linux - alternatives Arxivat 2015-10-07 a Wayback Machine.(anglès)
  55. GAlternatives - GUI per al selector d'alternatives a Linux(anglès)
  56. Comanda runghc (anglès)
  57. GHCi - guia d'usuari de l'intèrpret(anglès)
  58. GHCi - Declaracions de tipus i classes a l'intèrpret
  59. Hackage - Hayoo(anglès)
  60. Haskell wiki - Hoogle
  61. 61,0 61,1 61,2 Univ. de Girona - Introducció a la prog. funcional
  62. FOLDOC - Head Normal Form Arxivat 2016-03-03 a Wayback Machine.(anglès)
  63. 63,0 63,1 63,2 63,3 FOLDOC - Weak Head Normal Form Arxivat 2016-03-03 a Wayback Machine.(anglès)
  64. 64,0 64,1 HaskellWiki - Weak Head Normal Form
  65. El paquet deepseq(anglès)
  66. el mòdul Control.DeepSeq.Generics(anglès)
  67. «Haskell is a strict language». Arxivat de l'original el 2009-10-19. [Consulta: 24 octubre 2009].
  68. Haskell98 seq avalua a Head Normal Form(anglès)
  69. Haskell2010 seq avalua a Weak Head Normal Form(anglès)
  70. H2010 Language report - Strictness Flags(anglès)
  71. Eficiència i rendiment en tipus de dades (anglès)
  72. 72,0 72,1 BangPatterns - Avaluació estricta dels paràmetres Arxivat 2010-01-30 a Wayback Machine. (anglès)
  73. 73,0 73,1 GHC - Strict i StrictData(anglès)
  74. RealWorldHaskell - Optimitzacions - Strictness and Tail recursion(anglès)
  75. Haskellwiki - Tail recursion
  76. HaskellWiki - Thunk(anglès)
  77. Limitations of strictness analysis (anglès)
  78. Haskell.org - Lazy vs. Non-strict (anglès) Avaluació tardana i avaluació no-estricta
  79. Lazy pattern match(anglès)
  80. Lazy pattern match - Implications(anglès)
  81. Bash Shebang
  82. How to Script with Stack
  83. Haskell Wiki - Guia d'usuari de HUnit(anglès)
  84. paquet HUnit(anglès)
  85. Haskell Wiki - Introducció al QuickCheck(anglès)
  86. biblio. QuickCheck(anglès)
  87. Hspec: a testing framework for Haskell(anglès)
  88. Solving the diamond dependency problem(anglès) Solucionant el problema de la dependència en diamant
  89. HaskellWiki Cabal(anglès)
  90. Cabal User Guide(anglès)
  91. Repeat after me: "Cabal is not a Package Manager"(anglès)
  92. «Com crear un paquet Cabal». Arxivat de l'original el 2009-04-17. [Consulta: 1r juliol 2010].
  93. Cabal - Com instal·lar un paquet Cabal (anglès)
  94. Package versioning policy(anglès) Política de versionament dels paquets
  95. 95,0 95,1 Hackage - Rebost oficial d'aplicacions i biblioteques empaquetades amb Cabal Arxivat 2012-09-18 a Wayback Machine. (anglès)
  96. Cabal - Preguntes freqüents(anglès)
  97. Afegint paquets a una instal·lació Hugs Arxivat 2009-05-12 a Wayback Machine. (anglès)
  98. 98,0 98,1 Cabal FAQ - Conflictes de dependències(anglès)
  99. An introduction to cabal sandboxes Arxivat 2014-09-25 a Wayback Machine.(anglès)
  100. cabal-dev (anglès)
  101. HaskellWiki - Stackage(anglès)
  102. Com escriure (i empaquetar) un programa en Haskell(anglès)
  103. Actualitzant paquets a noves versions de GHC i biblioteques(anglès)
  104. HaskellWiki - ghc-pkg(anglès)
  105. Hackage - cabalg(anglès)
  106. [haskellstack.org/ The Haskell Tool Stack](anglès)
  107. How to play with Stack
  108. How to script with Stack
  109. How to build with Stack
  110. Stackage - rebostos de paquets amb compilació verificada respecte a una versió de GHC(anglès)
  111. Haskell wiki - Package versioning policy (anglès)
  112. cabal-progdeps (anglès)
  113. yackage (anglès)
  114. Docum de la Haskell Platform Arxivat 2013-01-26 a Wayback Machine.(anglès)
  115. Biblioteca Base de GHC - vegeu mòduls marcats Base(anglès)
  116. The Haskell Platform FAQ (anglès)
  117. E.Z. Yang - BackPack(anglès)
  118. HaskellWiki - Backpack(anglès)
  119. GHC wiki - Backpack(anglès)
  120. 120,0 120,1 A taste of Cabalized Backpack(anglès)
  121. Backpack: Retrofitting Haskell with Interfaces(anglès)
  122. MixML(anglès)
  123. 123,0 123,1 123,2 123,3 E. Z. Yang - Try Backpack(anglès)
  124. Try Backpack: Cabal packages
  125. Announcing Eta v0.8.6
  126. Paquet hlint que genera el programa del mateix nom(anglès)
  127. Leksah - Entorn gràfic de desenvolupament (IDE) per a Haskell Arxivat 2012-05-13 a Wayback Machine. (anglès)
  128. Instal·lació de l'entorn de desenvolupament Leksah(anglès)
  129. Endollable per a l'entorn de desenvolupament Eclipse (anglès)
  130. Fòrum StackOverflow - Visual Haskell(anglès)
  131. HaskellWiki - Internacionalització dels programes en Haskell(anglès)
  132. Implementacions de Haskell (anglès)
  133. Compilador GHC "Compilador Haskell de Glasgow" (anglès)
  134. Intèrpret del Glorious Compilador Haskell de Glasgow (anglès)
  135. Concurrència con Haskell(castellà)
  136. Glasgow Parallel Haskell(anglès)
  137. Un Tast de Haskell - Memoria Transaccional per Software[Enllaç no actiu] (anglès)
  138. Haskell Wiki - Memoria Transaccional per Software(anglès)
  139. Rerefons del GHC (anglès)
  140. HaskellWiki - Data Parallel Haskell(anglès)
  141. Nested Data Parallellism in Haskell(anglès)
  142. Hugs intèrpret de Haskell (anglès)
  143. Registres extensibles TRex de l'intèrpret Hugs Arxivat 2009-10-30 a Wayback Machine. (anglès)
  144. Compilador nhc98 (anglès)
  145. Utrecht Haskell Compiler (anglès)
  146. UHC/EHC rerefons de compilació (anglès)
  147. York Haskell Compiler(anglès)
  148. Generació de codi Javascript des d'YHC(anglès)
  149. Traçador de crides Hat Arxivat 2007-05-16 a Wayback Machine.(anglès)
  150. Jhc Haskell Compiler (anglès)
  151. Web de John Meacham creador del compilador JHC(anglès)
  152. LHC Haskell Compiler(anglès)
  153. Preprocessadors de Haskell Arxivat 2010-07-06 a Wayback Machine.(anglès)
  154. wiki de HaLVM: The Haskell Lightweight Virtual Machine Arxivat 2010-12-08 a Wayback Machine.(anglès)
  155. Run Haskell on Xen - No Operating System Required! Arxivat 2010-12-04 a Wayback Machine.(anglès)
  156. Adam Wick - The Haskell Lightweight VM
  157. The Compilador Haskell de Glasgow and LLVM(anglès)
  158. Rerefons LLVM de GHC(anglès)
  159. Brian McKenna - Haskell on Android using Eta
  160. UHC Jazy - rerefons a la màq. virtual Java(anglès)
  161. El compilador Haste (anglès)
  162. El compilador GhcJs (anglès)
  163. YHC/Javascript (anglès)
  164. Rerefons Javascript del compilador UHC(anglès)
  165. 165,0 165,1 PureScript.org(anglès)
  166. rerefons CLR a UHC Arxivat 2012-04-29 a Wayback Machine.(anglès)
  167. Running Haskell on the CLR(anglès)
  168. El Compilador del Deixeble Disciplinat DDC(anglès)
  169. Llenguatge OOHaskell Arxivat 2010-03-29 a Wayback Machine.(anglès)
  170. Llenguatge O'Haskell(anglès)
  171. Llenguatge Timber(anglès)
  172. Timber - Limitacions i problemàtiques(anglès)
  173. Open Quark(anglès)
  174. OpenQuark (llenguatge CAL sobre JVM) Arxivat 2011-09-02 a Wayback Machine.(anglès)
  175. Jaskell Arxivat 2006-02-20 a Wayback Machine.(anglès)
  176. El llenguatge Frege al GitHub

Vegeu també[modifica]

Enllaços externs[modifica]

A Wikimedia Commons hi ha contingut multimèdia relatiu a: Haskell