PureScript és un llenguatge de programació funcional de codi obert basat en el llenguatge Haskell adaptat a un substrat JavaScript amb especificitats de Node.js, del qual pren els tipus bàsics, l'avaluació estricta per defecte, amb una sintaxi lleugerament diferent al Haskell estàndard, i unes classes numèriques amb pedigrí matemàtic (L'equivalent de Num del Haskell és Ring, denotant l'estructura d'anell, el de Fractional és Field, el nom anglosaxó per al Cos, l'equivalent de Integral és EuclideanRing, anell euclidià).[3]

Infotaula de llenguatge de programacióPureScript
Tipusllenguatge de programació i llenguatge de programació purament funcional Modifica el valor a Wikidata
Data de creació2013 Modifica el valor a Wikidata
DissenyPhil Freeman[1][2]
Paradigma de programacióprogramació funcional amb avaluació estricta.[3]
Darrera versió estable0.13.6[4]
Influenciat perHaskell, JavaScript
Codi fontCodi font Modifica el valor a Wikidata
Llicènciallicència BSD de 3 clàusules Modifica el valor a Wikidata
Pàgina webpurescript.org Modifica el valor a Wikidata

En no comprometre's amb l'estàndard de Haskell, pot prescindir del RunTimeSystem que GHCJS emula oferint un resultat més lleuger i, a més a més, humanament llegible, incorporant extres com registres extensibles i efectes col·laterals més desgranats distingint els diferents efectes que el Haskell engloba dins IO (variables globals, accés als fitxers, excepcions), afegint-n'hi de nous.[5] Això ha canviat a la versió 12, amb l'eliminació de Eff basada en registres i substitució per la mònada Effect.[6]

Se'n pot fer ús per aplicacions a consola, en pàgines web i també en aplicacions de servidor basades en Node.js.

Després de l'èxit d'Elm en el desenvolupament d'interfícies d'usuari, PureScript apareix com una base més potent tècnicament, donat que Elm ha seguit un camí reduccionista per simplificar-ne l'ús evitant els predicats en els paràmetres de tipus (ús d'interfícies).[7]

L'utilitzen comercialment per la creació d'entorns de desenvolupament d'interfícies d'usuari en pàgines web, com es detalla tot seguit.

Metodologies per generar interfícies d'usuari modifica

Utilitzen la programació reactiva per generar pàgines web automodificables, amb arquitectures en llenguatge PureScript basats en la funcionalitat aportada per ReactJS i la interacció amb servidors web de dades JSON, HTML o bé XML:[8][9]

  • PureScript Pux[10] és una arquitectura PureScript basada en el sistema ReactJS que segueix l'arquitectura TEA de Elm. Proposa separació de components per mòduls amb tractament manual de la combinació d'estats i accions en un únic component ReactJS.[11][12]
  • Thermite[13] és una realització de Phil Freeman (l'autor de PureScript) que permet definir i combinar components ReactJS segons l'arquitectura MVC, basat en biblioteques PureScript que embolcallen la funcionalitat ReactJS en JavaScript.[8][14] Permet la combinació de components com a semigrup i el seu adreçament amb lents sobre l'estat conjunt (tipus producte dels estats individuals) i prismes (lents sobre tipus suma (unió discriminada) de les accions individuals). També permet l'arranjament de components en llista, on les accions vindran parametritzades per l'índex. Disposa d'una guia interactiva oficial.[15]
  • Halogen[16] hi introdueix el patró observador per facilitar la comunicació entre components pares i fills. També és de codi obert, desenvolupat per la companyia Slamdata.[17]
  • Permet definir encaixos (definit: slot) per a components, en una gramàtica específica (DSL) per descriure la presentació. La definició d'un encaix vindrà parametritzat per l'acció del subcomponent per comunicar-li que cal redibuixar-lo (paràmetre input); i també (paràmetre output) pel constructor de l'acció per tractar, al comp. pare, els missatges que el subcomponent envia cap amunt (verb raise).
  • El component pare pot enviar, al component de l'encaix, accions de consulta d'estat o bé de mutació que el controlador del component de l'encaix haurà de tractar.
  • Optic UI[18] és un marc de desenvolupament d'interfícies d'usuari basat en lents.[19]

Entorn de desenvolupament modifica

Disposa de compilador, intèrpret i avaluador en-línia.

Requereix el gestor de Node.js "npm", i l'eina "pulp".[20][21]

Hi ha dos gestors de paquets de biblioteques:

  • bower permet especificar versions exactes o mínimes de les dependències.[22]
  • psc-package es basa en rebostos de conjunts de biblioteques compatibles (compilació assegurada).[23][24]

El rebost general oficial de biblioteques és el rebost Pursuit que també conté un cercador de l'API.

Rerefons de compilació modifica

Especificitats del llenguatge modifica

Vegeu ref.[3]

# si hem instal·lat "bower"
$ pulp init # crea una aplicació basada en el gestor de biblioteques "bower"

# si hem instal·lat "psc-package"
$ pulp --psc-package init # crea una aplicació basada en el gestor de biblioteques "psc-package"

$ pulp repl # engega l'intèrpret

Algunes construccions esbiaixades cap al JavaScript i diferents del Haskell:

PSCi, version 0.11.7
Type :? for help
import Prelude -- no hi ha importacions implícites

-- el tipus dels literals numèrics és fix, a diferència del Haskell on el tipus depèn de l'estructura algebraica requerida per l'operador.

> :t [1,2,3] -- el tipus dels literals amb claus rectang. és (Array a), com al JavaScript, no pas com al Haskell
Array Int

> :t [] -- les claus buides denoten un Array buit. Per a les llistes cal fer servir Nil
forall t1. Array t1

> :t true -- els valors de l'àlgebra de Boole van en minúscules i el tipus és "Boolean", com al JS i no "Bool" com al Haskell
Boolean

> :t 1.5 -- el tipus dels literals Reals és Number, com al JS, i no Float/Double
Number 

-- L'operador (:) o `cons` està definit tant per a (Array a) Data.Array com per a (List a) (Data.List)
> :t 1:2:[]
Array Int

> import Data.Array ((..)) -- l'operador dels rangs (..) també està definit per a ambdós
> :t 1..5 -- els rangs no porten claus
Array Int -- el tipus dependrà de la signatura de l'operador visible

> :clear -- reset de l'intèrpret
> import Data.List (List(..), (:))
> :t 1:2:Nil -- amb (:) de Data.List això és una llista
List Int

> import Data.List.Lazy as LL -- l'"import" amb sobrenom evita la incorporació del contingut a l'espai de noms. Equival en Haskell a "import qualified"
> LL.fromFoldable (1:2:Nil) -- convertim a Lazy la llista estricta
fromStrict ((Cons 1 (Cons 2 Nil)))

> import Data.List as LS
> import Data.List.Lazy ((:))

> f :: Int -> LL.List Int
-- genera estrictament tots els elements d'una llista Lazy 
-- vegeu més avall seqüències definides recursivament amb avaluació tardana
> f x | x > 0 = x : f (x-1) 
> | otherwise = LL.nil -- llista buida

-- consum d'una llista tardana

import Data.List.Lazy (step, Step(Nil, Cons)) -- step força la desconstrucció

-- cal declarar totes les vars. d'una declaració de tipus a l'inici amb "forall" o bé el caràcter matemàtic ∀

mostraNElems :: forall a. Show a => Int -> LL.List a -> String 
mostraNElems n xs = go n (step xs)
 where
 go _ Nil = "Nil"
 go n (Cons x xs') | n > 0 = show x <> " : " <> go (n-1) (step xs') -- (<>) és l'"append" de Data.Semigroup
 | otherwise = ""

Les dades (data ...) estan completament avaluades, a diferència del Haskell estàndard on se'n retarda l'avaluació.

L'avaluació tardana de les expressions s'hi fa retardant l'avaluació amb una funció de Unit (Unit -> a), bé amb el mòdul Control.Lazy del paquet purescript-control,[27] o bé amb el tipus Lazy de Data.Lazy definit al paquet purescript-lazy.[28]

Hi ha llistes d'avaluació estricta (a Data.List) i d'avaluació tardana (a Data.List.Lazy), així com versions no-buides afegint .NonEmpty als corresponents noms de mòdul.[29]

Les conversions entre Number i Int no són al Prelude sinó al mòdul Data.Int de purescript-integers.[30]

toNumber :: Int -> Number

floor, ceil, round :: Number -> Int

Efectes col·laterals modifica

Els efectes col·laterals hi son més desgranats que al llenguatge Haskell, i es tracten amb un tipus extensible

  • amb la mònada Eff.[31]
    • CONSOLE: entrada/sortida a consola.[32]
    • FS: accessos al sistema de fitxers per als programes de servidor Node.js.[33]
    • DOM: interacció amb document web en una finestra del Navegador.[34]
    • TIMER: temporitzadors de JavaScript.[35]
    • EXCEPTION: excepcions.[36] Les excepcions es construeixen amb "error" i es disparen amb "throwException" i es cacen amb "catchException". throw strErr construeix i dispara.
  • amb la mònada Aff per als efectes asíncrons.[37]
    • Ajax.[38]
    • sol·licituds HTTP multiplataforma {NodeJs, Navegador, altre} a la xarxa.[39]

Això ha canviat a la versió 12 amb l'eliminació de Eff basada en registres (row-types) i conversió a Effect.[6]

Depuració modifica

  • La pila de traces de crida en cas d'excepció, hi ve incorporada (contràriament al compilador GHC de Haskell que requereix el RunTimeSystem d'ajustatge).

Seqüències definides recursivament modifica

Per exemple: següents x = x : següents (x+1) Per ser un llenguatge estricte, el càlcul provoca l'avaluació immediata del paràmetre recursiu i la consegüent petada de la pila.

Podem evitar-ho utilitzant l'expressió de la definició de Data.List.Lazy.cons que posterga, amb Data.Lazy.defer, l'avaluació del segon paràmetre.

$ pulp repl

PSCi, version 0.11.7
Type :? for help
import Prelude

> import Data.List.Lazy
> import Data.Lazy (defer) -- defer :: (Unit -> a) -> Lazy a

> següents x = List $ defer \_ -> Cons x $ següents (x+1)

> show $ take 3 $ següents 0
"fromStrict ((Cons 0 (Cons 1 (Cons 2 Nil))))"

Segons l'article.[40]

Programa Hola Món modifica

module Main where

import Prelude -- cal importar el mòdul Prelude explícitament

import Control.Monad.Eff (Eff) 
import Control.Monad.Eff.Console (CONSOLE, log)

-- cal declarar totes les vars. de la declaració de tipus a l'inici amb "forall" o bé el caràcter matemàtic ∀

main :: forall e. Eff (console :: CONSOLE | e) Unit -- efectes amb tipus extensible
main = do
 log "Hola Món!"

Referències modifica

  1. About the author(anglès)
  2. GitHub - Phil Freeman(anglès)
  3. 3,0 3,1 3,2 Purescript - Diferències amb Haskell(anglès)
  4. edicions(anglès)
  5. taylor.fausak.me - El Perquè de PureScript(anglès)
  6. 6,0 6,1 Why did PureScript go from Eff to Effect?(anglès)
  7. reasonablypolymorphic.com - Elm is wrong(anglès)
  8. 8,0 8,1 reactjs.org
  9. Youtube - Claudia Doppioslash - Building a Graphical IDE with Elm/Purescript(anglès)
  10. purescript-pux.org(anglès)
  11. Nesting component events Arxivat 2018-04-01 a Wayback Machine.(anglès)
  12. Guia a codeburst.io - Write React Components in PureScript with Pux
  13. purescript-thermite(anglès)
  14. Guia a functorial.com - Building a Task List Application with Thermite(anglès)
  15. Guia interactiva del Thermite
  16. Slamdata - purescript-halogen(anglès)
  17. Guia sobre Halogen a parsonsmatt.org(anglès)
  18. purescript-optic-ui(anglès)
  19. Guia a zrho.me - User Interfaces with Optics Arxivat 2016-07-13 a Wayback Machine.(anglès)
  20. PureScript - Getting started(anglès)
  21. Bower - A package manager for the web
  22. bower.io
  23. github.com - psc-package
  24. github.com - psc-package sets
  25. Purescript's c++ backend Arxivat 2018-03-12 a Wayback Machine.(anglès)
  26. Introducing PureScript Erlang backend(anglès)
  27. El paquet purescript-control(anglès)
  28. El paquet purescript-lazy(anglès)
  29. El paquet purescript-lists(anglès)
  30. El paquet purescript-integers(anglès)
  31. purescript-eff(anglès)
  32. purescript-console(anglès)
  33. purescript-node-fs(anglès)
  34. purescript-dom(anglès)
  35. purescript-js-timers(anglès)
  36. Mòdul Control.Monad.Eff.Exception(anglès)
  37. purescript-aff(anglès)
  38. purescript-affjax(anglès)
  39. purescript-requests(anglès)
  40. SchoolOfHaskell.org Building Lazy Lists in PureScript from recursive definitions(anglès)

Enllaços externs modifica