Frege (llenguatge de programació)

llenguatge de programació

Frege és un llenguatge de programació funcional, pur, d'avaluació tardana, de la família del llenguatge Haskell i influenciat pel Java. Té un sistema de tipatge fort amb tipus estàtics i inferència de tipus.

Infotaula de llenguatge de programacióFrege
Tipusllenguatge de programació purament funcional i llenguatge de programació Modifica el valor a Wikidata
EpònimGottlob Frege Modifica el valor a Wikidata
Paradigma de programacióprogramació funcional i purely functional programming (en) Tradueix Modifica el valor a Wikidata
Darrera versió estable3.23.288 ()
3.24 () Modifica el valor a Wikidata
Influenciat perJava i Haskell Modifica el valor a Wikidata
Sistema operatiumultiplataforma Modifica el valor a Wikidata
Extensió dels fitxersfr Modifica el valor a Wikidata
Codi fontCodi font Modifica el valor a Wikidata
Pàgina webgithub.com… Modifica el valor a Wikidata

Frege és creat per a l'ecosistema de la Màquina Virtual Java proporcionant facilitat d'interacció amb classes generades des d'altres llenguatges a la mateixa màquina virtual.

Frege és atribuïble a Ingo Wechsung (Language reference doc.).[1] Butlletí històric.[2]

Frege no és un dialecte de Haskell encara que hi té moltes concordances. Ve a ésser un assaig reeixit de Haskell, però més acadèmic que normatiu (per ex. la classe Mònada no incorpora el mètode fail, que s'inclou en una classe derivada MonadFail), incorporant al llenguatge trets amb paral·lelismes al model de la màquina virtual Java subjacent.

El nom del llenguatge de programació pretén honorar Gottlob Frege (un dels inventors de la currificació).

Programa Hola Món modifica

-- fitxer hola.fr
-- el mòdul equival a una ''classe Java'' (el nom pot ser jeràrquic com a pkgdir.NomDeLaClasseJava)
module Hola where 

main args = println $ "Hola món! heus aquí els arguments: " ++ show args

Compilant programes Frege modifica

Frege requereix un Java Development Kit (JDK) de la versió Java-7.

Com s'esmenta a la pàgina "Getting started"[3]

mkdir classes
java -Xss1m -jar <carpeta-d'instal·lació>/fregec.jar -d classes hola.fr

Aquí assumim que el compilador descarregat com a frege3.xx.vvv.jar ha estat reanomenat a fregec.jar.

Per executar el programa, cal esmentar-ne el nom de la classe d'arrencada.

$ java -cp classes:<carpeta-d'instal·lació>/fregec.jar Hola arg1 arg2

Hola món! heus aquí els arguments: ["arg1", "arg2"]
runtime 0.125 wallclock seconds.

Sobre Microsoft Windows el separador de la classpath cal que sigui ';' en comptes de ':'

Diferències amb Haskell modifica

Un resum de les diferències amb Haskell està llistat a la pàgina Differences between Frege and Haskell[Enllaç no actiu].

El tipus String està definit com una interfície amb les cadenes Java. L'op. (++) està lligat al (+) de les cadenes Java.[4] Però l'String de Frege implementa una classe ListLike que defineix els mètodes essencials de les llistes (Vegeu el mòdul PreludeList). Funcions de conversió al tipus corresponent al Haskell [Char]:

packed :: [Char] -> String
unpacked :: String -> [Char]

Literals:

-- els literals cert i fals no han de començar per majúscula.
-- frege: data Ordering = Lt | Eq | Gt
-- haskell: data Ordering = LT | EQ | GT

Els literals numèrics no es poden emprar com al Haskell associats a una classe de tipus (sobrecàrrega d'operacions), sinó, com al Java, associats a un tipus.

test = (*5) 5L -- error de tipus
--, l'aplicació parcial (*5) té tipus (:: Int -> Int) i no és aplicable al literal Long 5L

-- amb fromInt :: Num a => Int -> a

test = (* fromInt 5) 5L -- ara sí que passa la comprovació de tipus
fregeFromToList = 1..5 -- sense les claus [] :: [Int]
haskellFromToList = [1..5] -- :: (Num t, Enum t) => [t]

La classe Monad del Frege no inclou el mètode fail, que s'inclou en una classe separada MonadFail.[5]

Frege no implementa les excepcions del Haskell. Les excepcions de les crides a Java són caçades per la interfície de crides al llenguatge nadiu que han d'incorporar el resultat en un tipus (Either JException tipusDelResultat).

Les classes numèriques per a coma flotant no es corresponen amb les de Haskell.

-- el nom de la classe definida precedeix els requeriments del context.

class Real (Num r) => r where 
 --- l'operador de divisió real, que al Haskell està definit a la classe ''Fractional''
 (/) :: r -> r -> r

Exemples més elaborats modifica

Enumeració d'arguments modifica

module Test where

-- main :: [String] -> IO ()
main args = do
 println "Hello World!"
 case args of
 [] -> println "Ús: afegiu-hi qualque paràmetre"
 _ -> do
 println "vet aquí els vostres paràmetres:"
 let pairs = zip numeració args 
 forM_ pairs $ uncurry 
 -- funció anònima
 (\pos -> \arg -> do -- barra invertida a cadascun dels encaixos 
 -- els (->) entre paràmetres es poden estalviar
 print $ show pos ++ ". " 
 imprimeixArg arg
)
 where
 numeració = iterate (+1) 1 -- el [1..] del Haskell no està implementat -- :: [Int]

 -- composició de funcions (prefixar etiqueta i imprimir)
 imprimeixArg = println  ("arg: "++)

El tipus de dada Registre admet mètodes, per casar amb les classes de la JavaVM modifica

Els accessors per als camps fan servir la notació del punt (navegació de dades) i no comporten una funció a nivell de mòdul com fa el Haskell. (L'equivalent s'obté qualificant amb el Tipus: Tipus.nomDeCamp).

-- fitxer fregeRec.fr
module FregeRec where 
-- amb tipus escalars del Java
data TRec = RecConstructor { fld1 :: Long, fld2 :: String, fld3 :: Int} 
 where -- amb mètodes a continuació
 new cnt = RecConstructor 0L "abc" cnt -- inicialització posicional amb literals Java
 getProp1 (obj::TRec) = obj.fld1
 setProp1 (obj::TRec) v = obj.{fld1 = v} -- cal posar un punt davant la clàusula d'actualització
 incrProp1 (obj::TRec) = obj.{fld1 <- (+1L)} -- actualització amb una funció (al Haskell no hi és)

derive Eq TRec; derive Show TRec

-- fent servir els mètodes del registre amb estil navigacional.
getATRecObj cnt = ((TRec.new cnt
).setProp1 1L
).incrProp1

-- la propera línia dispararía un error!!: can't resolve `fld1` 
-- getField1 (obj::TRec) = fld1 obj -- fld1 no pertany a l'espai de noms del mòdul

data TRec2 = RecConstructor2 { fld4 :: Long, fld5 :: Float} 
 where -- alguns mètodes tot seguit
 new = RecConstructor2 { fld4 = 4L, fld5 = 0.0f} -- inicialització per nom amb literals Java
 getProp1 (obj::TRec2) = obj.fld4

derive Eq TRec2; derive Show TRec2
getATRec2Obj () = TRec2.new
-- file test.fr
module Test where

import FregeRec (TRec, getATRecObj, TRec2, getATRec2Obj)

-- definirem una classe de tipus (similar als "interface" del Java) 

class HasProp1Long t where
 getProp1 :: t -> Long

-- classe derivada
-- El nom de la classe definida precedeix el context !!

class PrintProp1 (HasProp1Long t) => t where 
 printProp1 :: t -> IO ()
 printProp1 rec = println $ "printProp1: " 
 ++ showLong rec.getProp1 
 where 
 showLong (longv::Long) = show longv

-- instanciem la classe derivada per als dos tipus definits.

instance PrintProp1 TRec
instance PrintProp1 TRec2

-- en instanciar PrintProp1 intenta també instanciar la classe base HasProp1Long
-- però aquesta defineix una funció ja implementada als mètodes dels tipus 
-- i el compilador ho troba tot bé.

-- main :: [String] -> IO ()
main args = do

 let myTRecObj = FregeRec.getATRecObj 1
 myTRec2Obj = FregeRec.getATRec2Obj ()

 println $ "myTRecObj: " ++ show myTRecObj
 println $ "myTRec2Obj: " ++ show myTRec2Obj

 printProp1 myTRecObj
 printProp1 myTRec2Obj

IORefs / Exportació d'identificadors modifica

  • El tipus IORef té mètodes com el Java {.new iniVal, .get, .put val}.
  • Identificadors exportats: L'exportació o no d'un símbol per part d'un mòdul no va com al Haskell sino mitjançant qualificadors d'accés private / protected / public (per omissió). Els etiquetats protected només s'exporten si el mòdul que els importa els menciona explícitament en una llista d'importació.
  • la definició d'operadors requereix cometes revesses. El rang de precedència (1..16) és diferent del del Haskell (0..9).
  • les crides a funcions sense paràmetres amb efectes col·laterals han de dur el paràmetre () (Unit) per evitar la memoïtzació.
module IORefTest where

-- definim un operador de composició d'esquerra a dreta (més fàcil de llegir)

infixr 3 `>>>` -- l'operador definit ha d'anar entre cometes revesses (diferència amb el Haskell)
f >>> g = g  f 

-- l'operador '>>=' té el mateix significat que al Haskell. (encadenament monàdic)

private incrCounter :: Enum a => IORef a -> IO a
private incrCounter enumRef = do

 enumRef.get >>= (succ >>> enumRef.put) 
 enumRef.get 

main _ = do
 refCnt <- IORef.new 0 -- :: IO (IORef Int)
 cnt <- incrCounter refCnt
 println $ "counter shows: " ++ show cnt

Interfície amb Java modifica

Cal afegir el qualificatiu native. Vegeu capítol "Native Interface" al Manual.

  • Els mètodes purs (quin resultat només depèn dels paràmetres) han de dur el qualif. pure.
  • Les definicions de tipus per a la interfície de classes Java amb estat han de dur un paràmetre fantasma (els que no figuren en la definició) per a l'estat corresponent al paràmetre de la Mònada (com ara (IO s)).
  • Els paràmetres amb valors que admeten null cal embolcallar-los en un tipus Maybe.
  • Els resultats de crides a Java que generen excepcions, cal embolcallar-los en un tipus Exception com ara Exception resultType sinònim de (Either JException resultType).
// file src/pkgdir/StringExtra.java
package pkgdir ;

public class StringExtra {
 // creant una classe per afegir funcionalitat

 public static int lastIndexOf(String str, char ch) {
 return str.lastIndexOf(ch); 
 }
}
-- file src/pkgdir/MyNativeInterface.fr
module pkgdir.MyNativeInterface where

-- els tipus nadius han d'incorporar un paràmetre fantasma, corresponen a l'espai d'avaluació de la Mònada
-- quin paràm. actual serà RealWorld cas de la mònada IO, o bé en cas de la mònada (ST s) la mateixa var. com al Haskell
data JRuntime s = native java.lang.Runtime 
 where
 -- FFI dels mètodes: "native" nom_Frege nom_Java :: tipus
 native jrtGetRuntime java.lang.Runtime.getRuntime :: () -> IO (JRuntime RealWorld) -- mètode estàtic 

 -- mètode és de la instància sempre que el primer paràmetre sigui del tipus definit, altrament estàtic
 native jrtFreeMemory freeMemory :: JRuntime RealWorld -> IO Long 

getFreeMemory :: () -> IO Long
getFreeMemory () = do
 runtime <- JRuntime.jrtGetRuntime ()
 runtime.jrtFreeMemory

-- quan la rutina nadiua llança excepcions
native getSysProp java.lang.System.getProperty :: String -> IO (Exception (Maybe String))

-- un mètode pur (quin resultat només depèn dels paràmetres)
pure native stringLastIndexOf StringExtra.lastIndexOf :: String -> Char -> Int
-- file src/pkgdir/Test1.fr
module pkgdir.Test where

import pkgdir.MyNativeInterface

-- testSysProp :: String -> IO ()
testSysProp name = do
 eitherRes <- getSysProp name -- :: IO (Exception (Maybe String))
 case eitherRes of
 Left excep -> println $ "exception: " ++ excep.getMessage
 Right maybeResult ->
 case maybeResult of
 Just strRes -> println $ "system prop. "++ name ++ " is: " ++ strRes
 Nothing -> println $ name ++ " system prop. is not defined"

-- testStrLastIndexOf :: String -> Char -> IO ()
testStrLastIndexOf string ch =
 println $ "stringLastIndexOf "++string++" "++ charToString ch ++" is: "++ show pos
 where 
 pos = stringLastIndexOf string ch 
 charToString ch = packed [ch]

main _ = do
 mem <- getFreeMemory ()
 println $ "freeMem: " ++ show mem
 testSysProp "myprop"
 testStrLastIndexOf "abc/def/ghi" '/'

executant:

# establir FREGE_HOME al directori d'instal·lació
# cd al directori pare del ''src''.
$ mkdir classes

# compilant els fonts Java
$ javac -cp classes:$FREGE_HOME/fregec.jar -d classes src/pkgdir/StringExtra.java

# compilant els fonts Frege
$ java -Xss1m -jar $FREGE_HOME/fregec.jar -d classes src/pkgdir/MyNativeInterface.fr src/pkgdir/Test1.fr

# execució:
$ java -cp classes:$FREGE_HOME/fregec.jar -Dmyprop=mypropval pkgdir.Test

freeMem: 28196256
system prop. myprop is: mypropval
stringLastIndexOf abc/def/ghi / is: 7

Relacionat modifica

Referències modifica

  1. Downloads[Enllaç no actiu] Language reference.
  2. What is frege (or what will it be)? Butlletí històric.
  3. Frege project - Getting started[Enllaç no actiu]
  4. «PreludeBase.fr». Arxivat de l'original el 2014-08-22. [Consulta: 21 maig 2012].
  5. «Monadic related functionality». Arxivat de l'original el 2015-05-12. [Consulta: 21 maig 2012].

Enllaços externs modifica

A fons modifica