OCaml - OCaml

OCaml
OCaml Logo.svg
Paradigma Multi-paradigma : funcional , imperativo , modular , orientado a objetos
Família ML
Projetado por Xavier Leroy , Jérôme Vouillon, Damien Doligez , Didier Rémy, Ascánder Suárez
Desenvolvedor INRIA
Apareceu pela primeira vez 1996 ; 25 anos atrás ( 1996 )
Versão estável
4.12.0  Edite isso no Wikidata / 24 de fevereiro de 2021 ; 6 meses atrás ( 24 de fevereiro de 2021 )
Disciplina de digitação Inferido , estático , forte , estrutural
Linguagem de implementação OCaml, C
Plataforma IA-32 , x86-64 , Power , SPARC , ARM 32-64
SO Plataforma cruzada : Unix , macOS , Windows
Licença LGPLv2.1
Extensões de nome de arquivo .ml, .mli
Local na rede Internet ocaml .org
Influenciado por
C , Caml , Modula-3 , Pascal , ML padrão
Influenciado
ATS , Coq , Elm , F # , F * , Haxe , Opa , Rust , Scala

OCaml ( / k Æ m əl / OH- KAM -əl , anteriormente Caml Objectivo ) é um de uso geral , linguagem de programação multi-paradigma que se estende a Caml dialeto de ML com orientada para objectos características. OCaml foi criado em 1996 por Xavier Leroy , Jérôme Vouillon, Damien Doligez , Didier Rémy, Ascánder Suárez e outros.

A cadeia de ferramentas OCaml inclui um interpretador de nível superior interativo , um compilador de bytecode , um compilador de código nativo otimizado, um depurador reversível e um gerenciador de pacotes (OPAM). OCaml foi inicialmente desenvolvido no contexto de prova automatizada de teoremas e tem uma presença exagerada em software de análise estática e métodos formais . Além dessas áreas, ele encontrou um uso sério em programação de sistemas , desenvolvimento web e engenharia financeira , entre outros domínios de aplicação.

A sigla CAML originalmente significava Categorical Abstract Machine Language , mas OCaml omite essa máquina abstrata . OCaml é um projeto de software livre e de código aberto gerenciado e mantido principalmente pelo Instituto Francês de Pesquisa em Ciência da Computação e Automação (INRIA). No início dos anos 2000, os elementos do OCaml foram adotados por muitas linguagens, principalmente F # e Scala .

Filosofia

As linguagens derivadas de ML são mais conhecidas por seus sistemas de tipos estáticos e compiladores de inferência de tipos . OCaml unifica a programação funcional , imperativa e orientada a objetos em um sistema de tipo semelhante ao ML. Portanto, os programadores não precisam estar muito familiarizados com o paradigma da linguagem funcional pura para usar OCaml.

Exigindo que o programador trabalhe dentro das restrições de seu sistema de tipos estáticos, OCaml elimina muitos dos problemas de tempo de execução relacionados a tipos associados a linguagens com tipos dinâmicos. Além disso, o compilador de inferência de tipo do OCaml reduz muito a necessidade de anotações de tipo manuais que são exigidas na maioria das linguagens de tipo estático. Por exemplo, o tipo de dados das variáveis ​​e a assinatura das funções geralmente não precisam ser declarados explicitamente, como acontece em linguagens como Java e C # , porque podem ser inferidos dos operadores e outras funções que são aplicadas às variáveis ​​e outros valores no código. O uso eficaz do sistema de tipos do OCaml pode exigir alguma sofisticação por parte do programador, mas essa disciplina é recompensada com um software confiável e de alto desempenho.

OCaml é talvez mais distinto de outras línguas com origem na academia por sua ênfase na performance. Seu sistema de tipo estático evita incompatibilidades de tipo de tempo de execução e, portanto, evita verificações de tipo e segurança de tempo de execução que sobrecarregam o desempenho de linguagens tipadas dinamicamente, enquanto ainda garantem a segurança de tempo de execução, exceto quando a verificação de limites de array é desligada ou quando alguns recursos de tipo inseguro, como serialização, são usados . Eles são raros o suficiente para que evitá-los seja possível na prática.

Além da sobrecarga de verificação de tipo, as linguagens de programação funcionais são, em geral, um desafio para compilar em um código de linguagem de máquina eficiente, devido a questões como o problema de funarg . Junto com loop padrão, registrador e otimizações de instrução , o compilador de otimização OCaml emprega métodos de análise de programa estático para otimizar a caixa de valor e a alocação de fechamento , ajudando a maximizar o desempenho do código resultante, mesmo que faça uso extensivo de construções de programação funcional.

Xavier Leroy afirmou que "OCaml oferece pelo menos 50% do desempenho de um compilador C decente", embora uma comparação direta seja impossível. Algumas funções na biblioteca padrão OCaml são implementadas com algoritmos mais rápidos do que funções equivalentes nas bibliotecas padrão de outras linguagens. Por exemplo, a implementação da união de conjuntos na biblioteca padrão OCaml em teoria é assintoticamente mais rápida do que a função equivalente nas bibliotecas padrão de linguagens imperativas (por exemplo, C ++, Java) porque a implementação OCaml explora a imutabilidade dos conjuntos para reutilizar partes da entrada conjuntos na saída (consulte a estrutura de dados persistente ).

Recursos

OCaml apresenta um sistema de tipo estático , inferência de tipo , polimorfismo paramétrico , recursão de cauda , correspondência de padrões , fechamentos lexicais de primeira classe , functores (módulos paramétricos) , tratamento de exceções e coleta de lixo automática de geração incremental .

OCaml é notável por estender a inferência de tipo no estilo ML para um sistema de objetos em uma linguagem de uso geral. Isso permite subtipagem estrutural , onde os tipos de objetos são compatíveis se suas assinaturas de método forem compatíveis, independentemente de sua herança declarada (um recurso incomum em linguagens tipadas estaticamente).

Uma interface de função estrangeira para vincular a primitivas C é fornecida, incluindo suporte de linguagem para matrizes numéricas eficientes em formatos compatíveis com C e Fortran . OCaml também suporta a criação de bibliotecas de funções OCaml que podem ser vinculadas a um programa principal em C, para que uma biblioteca OCaml possa ser distribuída para programadores C que não têm conhecimento ou instalação de OCaml.

A distribuição OCaml contém:

O compilador de código nativo está disponível para muitas plataformas, incluindo Unix , Microsoft Windows e Apple macOS . A portabilidade é alcançada por meio do suporte à geração de código nativo para as principais arquiteturas: IA-32 , X86-64 (AMD64), Power , RISC-V , ARM e ARM64 .

Bytecode OCaml e programas de código nativo podem ser escritos em um estilo multithread , com troca de contexto preemptiva. No entanto, como o coletor de lixo do sistema INRIA OCaml (que é a única implementação completa da linguagem atualmente disponível) não foi projetado para simultaneidade, o multiprocessamento simétrico não é suportado. Threads OCaml no mesmo processo são executados apenas por compartilhamento de tempo. No entanto, existem várias bibliotecas para computação distribuída, como Functory e ocamlnet / Plasma .

Ambiente de desenvolvimento

Desde 2011, muitas novas ferramentas e bibliotecas têm contribuído para o ambiente de desenvolvimento OCaml:

  • Ferramentas de desenvolvimento
    • opam é um gerenciador de pacotes para OCaml.
    • O Merlin fornece funcionalidade semelhante a IDE para vários editores, incluindo retrocesso de tipo, ir para a definição e preenchimento automático.
    • Dune é um sistema de construção combinável para OCaml.
    • OCamlformat é um formatador automático para OCaml.
    • ocaml-lsp-server é um protocolo de servidor de linguagem para integração OCaml IDE .
  • Web sites:
  • Compiladores alternativos para OCaml:
    • js_of_ocaml, desenvolvido pela equipe Ocsigen , é um compilador de otimização de OCaml para JavaScript .
    • BuckleScript , que também visa JavaScript , com foco na produção de saída JavaScript idiomática e legível.
    • ocamlcc é um compilador de OCaml para C, para complementar o compilador de código nativo para plataformas não suportadas.
    • OCamlJava, desenvolvido pela INRIA, é um compilador de OCaml para a máquina virtual Java (JVM).
    • OCaPic, desenvolvido pela Lip6, é um compilador OCaml para microcontroladores PIC .

Exemplos de código

Fragmentos de código OCaml são mais facilmente estudados inserindo-os no REPL de nível superior . Esta é uma sessão OCaml interativa que imprime os tipos inferidos de expressões resultantes ou definidas. O nível superior OCaml é iniciado simplesmente executando o programa OCaml:

$ ocaml
     Objective Caml version 3.09.0
#

O código pode então ser inserido no prompt "#". Por exemplo, para calcular 1 + 2 * 3:

# 1 + 2 * 3;;
- : int = 7

OCaml infere o tipo da expressão como "int" (um inteiro de precisão de máquina ) e fornece o resultado "7".

Olá Mundo

O seguinte programa "hello.ml":

print_endline "Hello World!"

pode ser compilado em um executável bytecode:

$ ocamlc hello.ml -o hello

ou compilado em um executável de código nativo otimizado:

$ ocamlopt hello.ml -o hello

e executado:

$ ./hello
Hello World!
$

O primeiro argumento para ocamlc, "hello.ml", especifica o arquivo de origem a ser compilado e o sinalizador "-o hello" especifica o arquivo de saída.

Somando uma lista de inteiros

As listas são um dos tipos de dados fundamentais no OCaml. O exemplo de código a seguir define uma soma de função recursiva que aceita um argumento, inteiros , que deveria ser uma lista de inteiros. Observe a palavra-chave que denota que a função é recursiva. A função itera recursivamente sobre a lista de inteiros fornecida e fornece uma soma dos elementos. A instrução match tem semelhanças com o elemento switch de C , embora seja muito mais geral. rec

let rec sum integers =                   (* Keyword rec means 'recursive'. *)
  match integers with
  | [] -> 0                              (* Yield 0 if integers is the empty 
                                            list []. *)
  | first :: rest -> first + sum rest;;  (* Recursive call if integers is a non-
                                            empty list; first is the first 
                                            element of the list, and rest is a 
                                            list of the rest of the elements, 
                                            possibly []. *)
  # sum [1;2;3;4;5];;
  - : int = 15

Outra maneira é usar a função de dobra padrão que funciona com listas.

let sum integers =
  List.fold_left (fun accumulator x -> accumulator + x) 0 integers;;
  # sum [1;2;3;4;5];;
  - : int = 15

Uma vez que a função anônima é simplesmente a aplicação do operador +, isso pode ser encurtado para:

let sum integers =
  List.fold_left (+) 0 integers

Além disso, pode-se omitir o argumento de lista fazendo uso de um aplicativo parcial :

let sum =
  List.fold_left (+) 0

Ordenação rápida

OCaml se presta a expressar algoritmos recursivos de forma concisa. O exemplo de código a seguir implementa um algoritmo semelhante ao quicksort que classifica uma lista em ordem crescente.

 let rec qsort = function
   | [] -> []
   | pivot :: rest ->
     let is_less x = x < pivot in
     let left, right = List.partition is_less rest in
     qsort left @ [pivot] @ qsort right

Problema de aniversario

O programa a seguir calcula o menor número de pessoas em uma sala para as quais a probabilidade de aniversários completamente únicos é inferior a 50% (o problema do aniversário , onde para 1 pessoa a probabilidade é 365/365 (ou 100%), para 2 é 364/365, para 3 é 364/365 × 363/365, etc.) (resposta = 23).

let year_size = 365.

let rec birthday_paradox prob people =
  let prob = (year_size -. float people) /. year_size *. prob  in
  if prob < 0.5 then
    Printf.printf "answer = %d\n" (people+1)
  else
    birthday_paradox prob (people+1)
;;

birthday_paradox 1.0 1

Numerais de igreja

O código a seguir define uma codificação de Igreja de números naturais , com sucessor (succ) e adição (adicionar). A Igreja numeral né uma função de ordem superior que aceita uma função fe um valor xe aplica-se fa xexatamente nvezes. Para converter um numeral de Igreja de um valor funcional em uma string, passamos a ele uma função que adiciona a string "S"à sua entrada e à string constante "0".

let zero f x = x
let succ n f x = f (n f x)
let one = succ zero
let two = succ (succ zero)
let add n1 n2 f x = n1 f (n2 f x)
let to_string n = n (fun k -> "S" ^ k) "0"
let _ = to_string (add (succ two) two)

Função fatorial de precisão arbitrária (bibliotecas)

Uma variedade de bibliotecas pode ser acessada diretamente no OCaml. Por exemplo, OCaml tem uma biblioteca interna para aritmética de precisão arbitrária . À medida que a função fatorial cresce muito rapidamente, ela ultrapassa rapidamente os números de precisão da máquina (normalmente 32 ou 64 bits). Portanto, o fatorial é um candidato adequado para a aritmética de precisão arbitrária.

No OCaml, o módulo Num (agora substituído pelo módulo ZArith) fornece aritmética de precisão arbitrária e pode ser carregado em um nível superior em execução usando:

# #use "topfind";;
# #require "num";;
# open Num;;

A função fatorial pode então ser escrita usando os operadores numéricos de precisão arbitrária = / , * / e - /  :

# let rec fact n =
    if n =/ Int 0 then Int 1 else n */ fact(n -/ Int 1);;
val fact : Num.num -> Num.num = <fun>

Esta função pode calcular fatoriais muito maiores, como 120 !:

# string_of_num (fact (Int 120));;
- : string =
"6689502913449127057588118054090372586752746333138029810295671352301633
55724496298936687416527198498130815763789321409055253440858940812185989
8481114389650005964960521256960000000000000000000000000000"

Triângulo (gráficos)

O programa a seguir renderiza um triângulo giratório em 2D usando OpenGL :

let () =
  ignore (Glut.init Sys.argv);
  Glut.initDisplayMode ~double_buffer:true ();
  ignore (Glut.createWindow ~title:"OpenGL Demo");
  let angle t = 10. *. t *. t in
  let render () =
    GlClear.clear [ `color ];
    GlMat.load_identity ();
    GlMat.rotate ~angle: (angle (Sys.time ())) ~z:1. ();
    GlDraw.begins `triangles;
    List.iter GlDraw.vertex2 [-1., -1.; 0., 1.; 1., -1.];
    GlDraw.ends ();
    Glut.swapBuffers () in
  GlMat.mode `modelview;
  Glut.displayFunc ~cb:render;
  Glut.idleFunc ~cb:(Some Glut.postRedisplay);
  Glut.mainLoop ()

As ligações do LablGL ao OpenGL são necessárias. O programa pode então ser compilado para bytecode com:

  $ ocamlc -I +lablGL lablglut.cma lablgl.cma simple.ml -o simple

ou para codificar nativ com:

  $ ocamlopt -I +lablGL lablglut.cmxa lablgl.cmxa simple.ml -o simple

ou, mais simplesmente, usando o comando ocamlfind build

  $ ocamlfind opt simple.ml -package lablgl.glut -linkpkg -o simple

e corra:

  $ ./simple

Programas gráficos 2D e 3D muito mais sofisticados e de alto desempenho podem ser desenvolvidos em OCaml. Graças ao uso de OpenGL e OCaml, os programas resultantes podem ser multiplataforma, compilando sem qualquer alteração nas principais plataformas.

Sequência de Fibonacci

O código a seguir calcula a sequência de Fibonacci de um número n inserido. Ele usa recursão de cauda e correspondência de padrões.

let fib n =
  let rec fib_aux m a b =
    match m with
    | 0 -> a
    | _ -> fib_aux (m - 1) b (a + b)
  in fib_aux n 0 1

Funções de ordem superior

As funções podem assumir funções como entrada e funções de retorno como resultado. Por exemplo, aplicar duas vezes a uma função f produz uma função que aplica f duas vezes ao seu argumento.

let twice (f : 'a -> 'a) = fun (x : 'a) -> f (f x);;
let inc (x : int) : int = x + 1;;
let add2 = twice inc;;
let inc_str (x : string) : string = x ^ " " ^ x;;
let add_str = twice(inc_str);;
  # add2 98;;
  - : int = 100
  # add_str "Test";;
  - : string = "Test Test Test Test"

A função usa duas vezes uma variável de tipo 'a para indicar que ela pode ser aplicada a qualquer função f mapeando de um tipo ' a para si mesma, ao invés de apenas para funções int-> int . Em particular, duas vezes pode até ser aplicado a si mesmo.

  # let fourtimes f = (twice twice) f;;
  val fourtimes : ('a -> 'a) -> 'a -> 'a = <fun>
  # let add4 = fourtimes inc;;
  val add4 : int -> int = <fun>
  # add4 98;;
  - : int = 102

Línguas derivadas

MetaOCaml

MetaOCaml é uma extensão de programação de vários estágios do OCaml que permite a compilação incremental de novo código de máquina durante o tempo de execução. Em algumas circunstâncias, acelerações significativas são possíveis usando a programação de vários estágios, porque informações mais detalhadas sobre os dados a serem processados ​​estão disponíveis no tempo de execução do que no tempo de compilação regular, de modo que o compilador incremental pode otimizar muitos casos de verificação de condição, etc.

Por exemplo: se em tempo de compilação é sabido que alguma função de potência é frequentemente necessária, mas o valor de é conhecido apenas em tempo de execução, uma função de potência de dois estágios pode ser usada no MetaOCaml: x -> x^nn

 let rec power n x =
   if n = 0
   then .<1>.
   else
     if even n
     then sqr (power (n/2) x)
     else .<.~x *. .~(power (n - 1) x)>.

Assim que nfor conhecido em tempo de execução, uma função de alimentação especializada e muito rápida pode ser criada:

 .<fun x -> .~(power 5 .<x>.)>.

O resultado é:

 fun x_1 -> (x_1 *
     let y_3 = 
         let y_2 = (x_1 * 1)
         in (y_2 * y_2)
     in (y_3 * y_3))

A nova função é compilada automaticamente.

Outras línguas derivadas

  • AtomCaml fornece uma primitiva de sincronização para execução atômica (transacional) de código.
  • Emily (2006) é um subconjunto do OCaml 3.08 que usa um verificador de regra de design para aplicar os princípios de segurança do modelo de capacidade de objeto .
  • F # é uma linguagem .NET Framework baseada em OCaml.
  • Fresh OCaml facilita a manipulação de nomes e fichários.
  • GCaml adiciona polimorfismo extensional ao OCaml, permitindo assim a sobrecarga e o empacotamento de tipo seguro.
  • JoCaml integra construções para o desenvolvimento de programas concorrentes e distribuídos.
  • OCamlDuce estende OCaml com recursos como expressões XML e tipos de expressão regular.
  • OCamlP3l é um sistema de programação paralela baseado em OCaml e na linguagem P3L.
  • Embora não seja realmente uma linguagem separada, o Reason é uma sintaxe alternativa do OCaml e uma cadeia de ferramentas para o OCaml criada no Facebook .

Software escrito em OCaml

Comercial

Várias dezenas de empresas usam OCaml até certo ponto. Exemplos notáveis ​​incluem:

Referências

links externos