Oz es un lenguaje de programación multiparadigma , desarrollado en el Laboratorio de Sistemas de Programación de la Universidad Católica de Lovaina , para la enseñanza de lenguajes de programación. Tiene un libro de texto canónico: Conceptos, técnicas y modelos de programación informática .
Oz fue diseñado por primera vez por Gert Smolka y sus estudiantes en 1991. En 1996, el desarrollo de Oz continuó en cooperación con el grupo de investigación de Seif Haridi y Peter Van Roy en el Instituto Sueco de Ciencias Informáticas . Desde 1999, Oz ha sido desarrollado continuamente por un grupo internacional, el Consorcio Mozart, que originalmente estaba formado por la Universidad del Sarre , el Instituto Sueco de Ciencias Informáticas y la Universidad Católica de Lovaina . En 2005, la responsabilidad de gestionar el desarrollo de Mozart se transfirió a un grupo central, la Junta de Mozart, con el propósito expreso de abrir el desarrollo de Mozart a una comunidad más grande.
El sistema de programación Mozart es la implementación principal de Oz. Se publica con una licencia de código abierto por el Consorcio Mozart. Mozart se ha adaptado a Unix , FreeBSD , Linux , Windows y macOS .
Oz [2] contiene la mayoría de los conceptos de los principales paradigmas de programación , incluyendo lógica, funcional (tanto evaluación perezosa como evaluación ansiosa ), imperativa, orientada a objetos, por restricciones, distribuida y concurrente. Oz tiene tanto una semántica formal simple (ver el capítulo 13 del libro mencionado a continuación) como una implementación eficiente. [ cita requerida ] Oz es un lenguaje orientado a la concurrencia , ya que el término fue introducido por Joe Armstrong, el diseñador principal del lenguaje Erlang . Un lenguaje orientado a la concurrencia hace que la concurrencia sea fácil de usar y eficiente. Oz admite un lenguaje de interfaz gráfica de usuario (GUI) canónico QTk. [3]
Además de la programación multiparadigma, las principales fortalezas de Oz están en la programación con restricciones y la programación distribuida . Debido a su diseño factorizado, Oz puede implementar con éxito un modelo de programación distribuida transparente a la red. Este modelo facilita la programación de aplicaciones abiertas y tolerantes a fallas dentro del lenguaje. Para la programación con restricciones, Oz introduce la idea de espacios de cómputo , que permiten estrategias de búsqueda y distribución definidas por el usuario ortogonales al dominio de restricciones.
Oz se basa en un lenguaje central con muy pocos tipos de datos que pueden ampliarse a otros más prácticos mediante azúcar sintáctica .
Estructuras de datos básicas:
circle(x:0 y:1 radius:3 color:blue style:dots)
. Aquí los términos x,y, radio, etc. se denominan características y los datos asociados con las características (en este caso 0,1,3, etc.) son los valores. circle(1:0 2:1 3:3 4:blue 5:dots)
.'|' ( 2 '|' ( 4 '|' ( 6 '|' ( 8 nil )))) % como registro. 2 |( 4 |( 6 |( 8 | nil ))) % con algo de azúcar sintáctica 2 | 4 | 6 | 8 | nil % más azúcar sintáctica [ 2 4 6 8 ] % aún más azúcar sintáctica
Esas estructuras de datos son valores (constantes), de primera clase y con verificación de tipo dinámica . Los nombres de las variables en Oz comienzan con una letra mayúscula para distinguirlos de los literales [4] que siempre comienzan con una letra minúscula.
Las funciones [5] son valores de primera clase, lo que permite una programación funcional de orden superior :
diversión { Hecho N } si N =< 0 entonces 1 de lo contrario N * { Hecho N - 1 } fin fin
fun { Comb N K } { Fact N } div ({ Fact K } * { Fact N - K }) % de números enteros no pueden desbordarse en Oz (a menos que no quede memoria) end fun { SumList List } caso Lista de nulos entonces 0 [] H | T entonces H + { SumList T } % coincidencia de patrones en listas fin fin
Las funciones se pueden utilizar con variables libres y variables ligadas. Los valores de las variables libres se encuentran utilizando el alcance léxico estático . [6]
Las funciones son como otros objetos de Oz. Una función se puede pasar como atributo a otras funciones o se puede devolver en una función.
fun { Cuadrado N } % Una función general N * N fin fun { Map F Xs } % F es una función aquí - caso de programación de orden superior Xs de nulo entonces nulo [] X | Xr entonces { F X }|{ Map F Xr } fin fin %usage { Explorar { Mapa cuadrado [ 1 2 3 ]}} %browses [1 4 9]
Al igual que muchos otros lenguajes funcionales, Oz admite el uso de funciones anónimas (es decir, funciones que no tienen nombre) en la programación de orden superior. Para indicarlas se utiliza el símbolo $.
A continuación, se define de forma anónima la función cuadrada y se pasa, provocando [1 4 9]
su exploración.
{ Explorar { Mapa divertido { $ N } N * N fin [ 1 2 3 ]}}
Como las funciones anónimas no tienen nombres, no es posible definir funciones anónimas recursivas.
Se supone que las funciones en Oz deben devolver un valor en la última declaración encontrada en el cuerpo de la función durante su ejecución. En el ejemplo siguiente, la función Ret devuelve 5 si X > 0 y -5 en caso contrario.
declarar fun { Ret X } si X > 0 entonces 5 de lo contrario ~ 5 fin fin
Pero Oz también proporciona una función en caso de que una función no deba devolver valores. Estas funciones se denominan procedimientos. [7] Los procedimientos se definen utilizando la construcción "proc" de la siguiente manera:
declarar proc { Ret X } si X > 0 entonces { Examinar 5 } de lo contrario { Examinar ~ 5 } fin fin
El ejemplo anterior no devuelve ningún valor, solo imprime 5 o -5 en el navegador Oz dependiendo del signo de X.
Cuando el programa encuentra una variable no vinculada, espera un valor. Por ejemplo, a continuación, el subproceso esperará hasta que tanto X como Y estén vinculados a un valor antes de mostrar el valor de Z.
hilo Z = X + Y { Explorar Z } fin hilo X = 40 fin hilo Y = 2 fin
El valor de una variable de flujo de datos no se puede cambiar una vez que está vinculada:
X = 1 X = 2 % de error
Las variables de flujo de datos facilitan la creación de agentes de transmisión simultáneos:
diversión { Ints N Max } si N == Max entonces nulo de lo contrario { Retraso 1000 } N |{ Ints N + 1 Max } fin fin fun { Sum S Stream } caso Stream de nulo entonces S [] H | T entonces S |{ Sum H + S T } fin fin local X Y en el hilo X = { Ints 0 1000 } fin del hilo Y = { Suma 0 X } fin { Explorar Y } fin
Debido a la forma en que funcionan las variables de flujo de datos, es posible colocar subprocesos en cualquier parte de un programa y garantizar que obtendrán el mismo resultado. Esto hace que la programación concurrente sea muy fácil. Los subprocesos son muy económicos: es posible tener 100.000 subprocesos ejecutándose a la vez. [8]
Este ejemplo calcula un flujo de números primos utilizando el algoritmo de división de prueba creando recursivamente agentes de flujo concurrentes que filtran los números no primos:
fun { Sieve Xs } caso Xs de nulo entonces nulo [] X | Xr entonces Ys en hilo Ys = { Filter Xr fun { $ Y } Y mod X \ = 0 fin } fin X |{ Sieve Ys } fin fin
Oz utiliza la evaluación diligente de forma predeterminada, pero es posible la evaluación perezosa [9] . A continuación, el hecho solo se calcula cuando se necesita el valor de X para calcular el valor de Y.
divertido perezoso { Hecho N } si N =< 0 entonces 1 de lo contrario N * { Hecho N - 1 } fin fin local X Y en X = { Hecho 100 } Y = X + 1 fin
La evaluación diferida ofrece la posibilidad de almacenar estructuras de datos verdaderamente infinitas en Oz. El poder de la evaluación diferida se puede ver en el siguiente ejemplo de código:
declarar fun lazy { Fusionar Xs Ys } caso Xs # Ys de ( X | Xr ) # ( Y | Yr ) entonces si X < Y entonces X |{ Fusionar Xr Ys } elseif X > Y entonces Y |{ Fusionar Xs Yr } else X |{ Fusionar Xr Yr } fin fin fin divertido perezoso { Times N Xs } caso Xs de nulo entonces nulo [] X | Xr entonces N * X |{ Times N Xr } fin fin declarar H H = 1 | { Fusionar { Multiplicado por 2 H } { Fusionar { Multiplicado por 3 H } { Multiplicado por 5 H }}} { Explorar { Lista . tomar H 6 }}
El código anterior calcula de manera elegante todos los números regulares [10] en una lista infinita. Los números reales se calculan solo cuando son necesarios.
El modelo concurrente declarativo se puede ampliar con el paso de mensajes a través de una semántica simple:
declarar puerto de flujo local en puerto = { NewPort Stream } { Puerto de envío 1 } % El flujo ahora es 1|_ ('_' indica una variable no vinculada y sin nombre) { Puerto de envío 2 } % El flujo ahora es 1|2|_ ... { Puerto de envío n } % El flujo ahora es 1|2| .. |n|_ fin
Con un puerto y un hilo se pueden definir agentes asincrónicos:
divertido { NewAgent Init Fun } Mensaje de salida en hilo { FoldL Msg Fun Init Out } fin { NewPort Msg } fin
Es posible ampliar el modelo declarativo para que admita la programación orientada a objetos y a estados con una semántica muy simple. Para crear una nueva estructura de datos mutables denominada Celdas:
local A X en A = { NewCell 0 } A : = 1 % cambia el valor de A a 1 X = @ A % @ se usa para acceder al valor de A fin
Con estos sencillos cambios semánticos, se puede dar soporte a todo el paradigma orientado a objetos. Con un poco de azúcar sintáctica, la programación orientada a objetos se integra bien en Oz.
clase Contador attr val meth init ( Valor ) val : = Valor fin meth browse { Explorar @ val } fin meth inc ( Valor ) val : = @ val + Valor fin fin C local en C = { Nuevo contador init ( 0 )} { C inc ( 6 )} { C browse } fin
La velocidad de ejecución de un programa producido por el compilador Mozart (versión 1.4.0 que implementa Oz 3) es muy lenta. En un conjunto de pruebas de referencia de 2012, fue en promedio unas 50 veces más lenta que la de la Colección de compiladores GNU (GCC) para el lenguaje C. [11]
{{cite web}}
: CS1 maint: copia archivada como título ( enlace )