OCaml

OCaml
Logo.
İlk sürüm tarihi 1987 (CAML), 1996 (OCaml)
paradigma Çok paradigma  : zorunlu , işlevsel , nesne yönelimli
geliştirici Hindistan
Son sürüm 4.12.0 (24 Şubat 2021)
Yazıyor Güçlü , statik
lehçeler JoCaml, Taze OCaml, GCaml, MetaOCaml, OCamlDuce, OcamlP3L
Tarafından etkilenmiş makine öğrenimi
Etkilenen F# , Pas , OPA , Scala
Yazılmış OCaml
İşletim sistemi Çapraz platform
Lisans LGPL 2.1
İnternet sitesi ocaml.org
Dosya uzantısı ml ve ml

Eskiden Objective Caml olarak bilinen OCaml , Xavier Leroy , Jérôme Vouillon , Damien Dolurez , Didier Rémy ve onların işbirlikçileri tarafından 1996 yılında oluşturulan Caml programlama dilinin en gelişmiş uygulamasıdır . ML dil ailesinden olan bu dil, esas olarak Inria tarafından yönetilen ve sürdürülen bir açık kaynak projesidir .

OCaml, diğer şeylerin yanı sıra bir nesne programlama katmanı eklediği Caml Light'ın halefidir . CAML kısaltması , artık OCaml'in son sürümlerinde kullanılmayan soyut bir makine modeli olan Kategorik Soyut Makine Dili'nden gelir .

Taşınabilir ve güçlü OCaml, Unison dosya senkronizasyon yazılımı , Coq resmi kanıt yardımcısı veya Facebook Messenger'ın web sürümü gibi çeşitli projelerde kullanılır . Dilin sembolik işleme olanakları, Microsoft tarafından yazılan Windows pilotları için SLAM projesi veya Airbus A380'lerin belirli yerleşik sistemleri için ASTRÉE gibi statik doğrulama araçlarının geliştirilmesine izin verir .

Prensipler

Caml , zorunlu programlamaya izin veren özelliklerle zenginleştirilmiş işlevsel bir dildir . OCaml, nesne yönelimli programlama ve modüler programlamayı etkinleştirerek dilin olanaklarını genişletir . Tüm bu nedenlerle OCaml, çok paradigmalı diller kategorisine girer .

Bu farklı kavramları, statik , güçlü ve çıkarsanmış bir tipleme ile karakterize edilen, ML'den devralınan bir tür sisteminde bütünleştirir .

Tip sistemi, karmaşık veri yapılarının kolayca işlenmesine izin verir: cebirsel türleri , yani hiyerarşik ve potansiyel olarak özyinelemeli türleri (listeler, ağaçlar, vb.) kolayca temsil edebilir ve kalıp eşleştirmeyi kullanarak bunları kolayca değiştirebiliriz . Bu, OCaml'i derleyiciler gibi karmaşık veri yapılarının işlenmesini gerektiren alanlarda tercih edilen bir dil haline getirir .

Güçlü yazarak , hem de açık bellek manipülasyon (a varlığı yokluğu çöp toplayıcısı ) OCaml çok güvenli bir dil yapar. Yerel bir kod derleyicisinin varlığı sayesinde performansıyla da ünlüdür .

Tarih

Caml dil hangi ML programlama dilinin toplantıdan doğdu Formel ekibi de INRIA ilgi olmuştur erken beri 1980'lerin ve Guy Cousineau en kategorik soyut makine CAM Pierre-Louis Curien çalışmalarına dayalı, 1984 . Ascander Suarez (o sırada Paris Diderot Üniversitesi'nde doktora öğrencisiydi ) tarafından yazılan ve daha sonra Pierre Weis ve Michel Mauny tarafından sürdürülen ilk uygulama 1987'de yayınlandı . Inria ekibi, bir dili kendi ihtiyaçlarına göre uyarlamak ve geliştirmeye devam etmek istediği için dil, ML babasından yavaş yavaş farklılaştı.

CAM'nin sınırlamaları , 1990 yılında Xavier Leroy tarafından Caml Light adı altında geliştirilen yeni bir uygulamanın oluşturulmasına yol açtı . Son versiyonu da dahil olmak üzere bu uygulama bugün eğitimde hala kullanılmaktadır , Sistem artık INRIA tarafından sağlanmasa da, C ile kodlanmış bir tercüman bayt kodu ( bytecode ) aracılığıyla çalışır , bu da ona büyük taşınabilirlik sağlar. Damien Dolurez tarafından tasarlanan bellek yönetim sistemi de Caml Light'ta ortaya çıktı. In 1995 , Xavier Leroy Caml bir versiyonu olarak adlandırılan yayınlanan Caml Özel Işık yerli kod derleyici ve Standart ML modüllerin esinlenerek bir modül sistemini tanıttı.

İlk kez 1996 yılında yayınlanan OCaml, Caml'a Didier Rémy ve Jérôme Vouillon tarafından tasarlanan bir nesne sistemi getiriyor. Polimorfik değişkenler veya etiketler gibi bazı gelişmiş özellikler (bir fonksiyona verilen argümanları konumlarından ziyade adlarına göre ayırt etmeye izin verir) 2000 yılında Jacques Garrigue tarafından tanıtıldı . OCaml o zamandan beri nispeten stabilize olmuştur (bir spesifikasyonun olmamasına rağmen, yürürlükteki belge Inria tarafından tutulan resmi kılavuzdur ). OCaml'in birçok lehçesi ortaya çıktı ve programlama dillerinin belirli yönlerini keşfetmeye devam ediyor (eşzamanlılık, paralellik, tembel değerlendirme, XML entegrasyonu…); Türetilmiş diller bölümüne bakın .

Temel özellikleri

Fonksiyonel dil

OCaml, işlevsel dillerin ortak özelliklerinin çoğuna, özellikle de üst düzey işlevler ve kapanışlar ( kapamalar ) ve kuyruk özyineleme için iyi bir desteğe sahiptir .

Yazıyor

OCaml statik yazma, derleme zamanında, çalışma zamanında sorunlara neden olabilecek çok sayıda programlama hatasını algılar. Ancak, diğer dillerin çoğundan farklı olarak, kullandığınız değişkenlerin türünü belirtmeniz gerekmez. Gerçekten de Caml, değişkenlerin türünü, kullanıldıkları bağlamdan belirlemesine izin veren bir tür çıkarım algoritmasına sahiptir.

ML tipleme sistemi, parametrik polimorfizmi , yani değeri tanımlandığında bölümleri belirsiz olacak türleri destekler . Otomatik olan bu özellik, Java veya C#' daki jeneriklerle veya C++' daki şablonlarla karşılaştırılabilir bir jenerik sağlar .

Bununla birlikte, nesne yönelimli programlama gibi gelişmiş işlevlerin entegrasyonunun gerektirdiği ML yazmanın uzantıları, belirli durumlarda tür sistemini karmaşıklaştırır: bu işlevlerin kullanımı, programcı için bir öğrenme süresi gerektirebilir. karmaşık tip sistemlere mutlaka aşinadır.

filtreleme

Desen eşleştirme (in English  : desen eşleştirme ) Caml dilinin temel bir unsurdur. Geleneksel koşullardan daha esnek bir yazma sayesinde kodu hafifletmeyi mümkün kılar ve kapsamlılık bir kontrolün amacıdır: derleyici, eksik bir filtreleme tespit edildiğinde bir karşı örnek önerir. Örneğin, aşağıdaki kod derlenir ancak bir uyarıya neden olur:

# type etat = Actif | Inactif | Inconnu;; type etat = Actif | Inactif | Inconnu # let est_actif = function # | Actif -> true # | Inactif -> false;; val est_actif : etat -> bool = <fun> Warning P: this pattern-matching is not exhaustive. Here is an example of a value that is not matched: Inconnu

Bu nedenle program, is_active işlevi Active veya Inactive durumuyla çağrıldığında çalışır , ancak Unknown ise, işlev Match_failure istisnasını atar .

Modüller

Modüller (örneğin, tüm listeler manipülasyon fonksiyonları Listesi modülünde olan) türlerini içeren yapılar ve mantıksal ilgili değerler hiyerarşisine programı kırmak için izin verir. ML ailesinin soyundan gelenler, şu anda ad alanlarına sahip olmanın yanı sıra soyutlama (uygulaması gizli olan erişilebilir değerler) ve birleştirilebilirlik (değerler) uygulamasına izin veren en gelişmiş modül sistemlerine sahip dillerdir. belirli bir arayüze yanıt verdikleri sürece farklı modüllerin üzerine kurulabilir).

Böylece, sözdizimsel yapının üç sözdizimsel birimi yapılar, arayüzler ve modüllerdir. Yapılar, modüllerin uygulanmasını içerir, arayüzler, onlardan erişilebilen değerleri tanımlar (uygulaması gösterilmeyen değerler soyut değerlerdir ve modülün uygulanmasında hiç görünmeyen değerlerdir. nesne yönelimli programlamadaki özel yöntemler gibi erişilemez). Bir modülün birden çok arabirimi olabilir (hepsi uygulama türleriyle uyumlu olduğu sürece) ve birden çok modül tek bir arabirimi doğrulayabilir. Fonksiyonlar, diğer yapılar tarafından parametrelendirilen yapılardır; örneğin, OCaml standart kitaplığının karma tabloları (Hashtbl modülü), bir tür, anahtarlar arasında bir eşitlik işlevi ve bir karma işlevden oluşan arabirimi uygulayan herhangi bir yapıyı parametre olarak alan bir işlev olarak kullanılabilir. .

Nesne odaklı

OCaml, klasik nesne dilleri tarafından kullanılanlarla karşılaştırılabilir bir nesne sistemine ML yazmanın uzantısıyla özellikle ayırt edilir . Bu, ilgili miras ağaçlarından bağımsız olarak, yöntemlerinin türleri uyumluysa nesnelerin uyumlu türlerde olduğu yapısal alt tiplemeye izin verir . Dinamik dillerin ördek tiplemesinin eşdeğeri olarak kabul edilebilecek bu işlevsellik, genel olarak işlevsel bir dilde nesne kavramlarının doğal bir entegrasyonunu sağlar.

Bu nedenle, her sınıfın bir tür tanımladığı C++ veya Java gibi nesne yönelimli dillerin aksine , OCaml sınıfları daha çok tür kısaltmalarını tanımlar. Gerçekten de, yöntemlerin türü uyumlu olduğu sürece, aynı bağlamda iki farklı sınıftan iki nesne farksız olarak kullanılabilir. OCaml'in nesne katmanının bu özelliği, yaygın olarak kabul edilen çok sayıda ilkeyi bozar: örneğin kalıtım olmadan alt tipleme yapmak gerçekten de mümkündür. Polimorfik taraf, ters prensibi bozar. Nadir olmasına rağmen, alt tipleme olmaksızın kalıtım vakalarını gösteren kod örnekleri de mevcuttur. Nesne katmanının gücü, homojenliğinde ve OCaml dilinin felsefesine ve ruhuna mükemmel entegrasyonunda yatar. Nitelikleri değiştirilemeyen ve varsa yöntemleri, niteliklerin güncellenmesiyle veya anlık nesnelerin tanımıyla veya anında bir kopya döndüren işlevsel nesneler de mümkündür.

dağıtım

OCaml dağıtımı şunları içerir:

  • Bir etkileşimli yorumlayıcı (ocaml);
  • bir bayt kodu derleyicisi (ocamlc) ve bayt kodu yorumlayıcısı (ocamlrun);
  • yerel bir derleyici (ocamlopt);
  • sözlüksel (ocamllex) ve sözdizimsel (ocamlyacc) analizör üreteçleri ;
  • dil sözdiziminin genişletilmesine veya değiştirilmesine izin veren bir önişlemci (camlp4);
  • Bir adım adım ayıklayıcı geri alma (ocamldebug) ile;
  • profil oluşturma araçları  ;
  • bir dokümantasyon oluşturucu (ocamldoc);
  • OCaml 3.10'dan beri otomatik bir derleme yöneticisi (ocamlbuild);
  • Bir standart değişik kitaplığı .

OCaml araçları Windows , GNU/Linux veya MacOS'ta düzenli olarak kullanılmaktadır , ancak BSD gibi diğer sistemlerde de mevcuttur .

Bayt kodu derleyicisi, daha sonra ocamlrun tarafından yorumlanan dosyalar oluşturmak için kullanılır. Bayt kodu olan platform bağımsız, bu büyük sağlamaktadır taşınabilirliği (ocamlrun olabilir önsel fonksiyonel C Derleyici destekleyen herhangi bir platformunda derlenebilir). Yerel derleyici, büyük ölçüde geliştirilmiş performans için üretilen yürütülebilir dosyanın taşınabilirliğini feda eden platforma özel derleme kodu üretir. IA-32 , PowerPC , AMD64 , Alpha , Sparc , Mips , IA-64 , HPPA ve StrongARM platformları için yerel bir derleyici mevcuttur .

Uyumluluk arabirimi, OCaml kodunu C'deki temel öğelere bağlamanıza olanak tanır ve kayan nokta dizilerinin biçimi, C ve Fortran ile uyumludur . OCaml ayrıca OCaml kodunun bir C programına entegrasyonuna izin vererek, OCaml kitaplıklarının OCaml'i bilmelerine ve hatta kurmalarına gerek kalmadan C programcılarına dağıtılmasını mümkün kılar.

OCaml araçları, bazı kitaplıklar ve C'de kodlanmış bayt kodu yorumlayıcısı dışında, çoğunlukla OCaml'de kodlanmıştır. Özellikle, yerel derleyici tamamen OCaml'de kodlanmıştır.

Hafıza yönetimi

OCaml, Java gibi, nesiller boyu artımlı çöp toplama sayesinde otomatikleştirilmiş bir bellek yönetimine sahiptir . Bu, özellikle işlevsel bir dile uyarlanmıştır (küçük nesnelerin hızlı bir şekilde tahsis edilmesi / serbest bırakılması için optimize edilmiştir) ve bu nedenle programların performansı üzerinde kayda değer bir etkisi yoktur. Atipik bellek kullanımı durumlarında verimli kalacak şekilde yapılandırılabilir.

Performanslar

OCaml, mükemmel performansla akademik çevrelerde geliştirilen çoğu dilden farklıdır. . Yerel kod oluşturucu tarafından gerçekleştirilen "klasik" yerel optimizasyonlara ek olarak,performanslar, dilin işlevsel ve statik ve güçlü bir şekilde yazılmış yapısından avantajlı bir şekilde yararlanır.

Bu nedenle, yazma bilgileri derleme zamanında tamamen belirlenir ve yerel kodda yeniden üretilmesi gerekmez; bu, diğer şeylerin yanı sıra, çalışma zamanında yazma testlerini tamamen kaldırmaya izin verir. Öte yandan, standart kitaplıktan bazı algoritmalar, saf işlevsel veri yapılarının ilginç özelliklerinden yararlanır: bu nedenle, küme birleştirme algoritması, değişmezliklerini kullandığı için, zorunlu dillerinkinden asimptotik olarak daha hızlıdır. çıktı kümesini oluşturacak kümeler (bu, kalıcı veri yapıları için yol kopyalama tekniğidir ).

Tarihsel olarak, işlevsel diller bazı programcılar tarafından yavaş olarak kabul edildi, çünkü doğal olarak nasıl verimli bir şekilde derleneceğimizi bilmediğimiz kavramların (bellek kurtarma, kısmi uygulama vb.) uygulanmasını gerektiriyorlar; derleme tekniklerindeki ilerlemeler o zamandan beri zorunlu dillerin ilk avantajını yakalamayı mümkün kıldı. OCaml, dilin bu kısımlarını verimli bir şekilde optimize ederek ve işlevsel dillerin sık tahsisine uyarlanmış bir çöp toplayıcı uygulayarak , işlevsel programlamanın yeniden keşfedilen verimliliğini gösteren ilk işlevsel dillerden biriydi.

Genel olarak, yürütme hızı, C'deki eşdeğer bir kodun hızından biraz daha düşüktür . Xavier Leroy temkinli bir şekilde "makul bir C derleyicisinin performansının en az %50'si kadar performans"tan söz ediyor. Bu tahminler o zamandan beri çok sayıda kriter tarafından onaylandı. Uygulamada, programlar, genel olarak, bazen daha hızlı C'den düşük, bazen büyük ölçüde talihsiz bir etkileşim yavaşlatılır her iki yönde de uç ile (bu aralıkta (yani Cı-kod 1 ila 2 kez) kalmak çöp toplayıcısı , bu her durumda Python veya Ruby gibi yerel olarak derlenmeyen ve Java veya C# gibi anında derlenen statik dillerle karşılaştırılabilir en yeni dillerden hala daha hızlı .

kullanmak

Araştırma çevrelerinden kaynaklanan OCaml dili, bazı güncel programlama dillerinin reklam gücünden faydalanmamaktadır. Bu nedenle, genel bilgisayar halkı (ve çoğu işlevsel dil) tarafından nispeten bilinmezliğini korumaktadır, ancak yine de, dilin niteliklerinin popülerlik eksikliğinden öncelikli olduğu birkaç niş içinde sağlam bir şekilde kurulmuştur.

Eğitim

OCaml, Grandes écoles'e giriş sınavları için bilgisayar seçeneği testleri açısından Caml Light'ın yerini aldığı Fransızca hazırlık sınıfları tarafından kullanılan dildir . Bu öğretim çerçevesinde kullanılan belgeler, işlevsel programlama ve matematik arasındaki bağlantıları ve ML ailesinin dillerinin algoritmaları öğretmek için yararlı olan özyinelemeli veri yapılarını işlemedeki kolaylığını vurgulamaktadır .

Akademide, bazı fonksiyonel programlama derslerinde tercih edilen Haskell dili ile rekabetten muzdariptir , çünkü diğer şeylerin yanı sıra, herhangi bir zorunlu programlama kavramını almaz .

Araştırma

OCaml, arama dünyasında oldukça kullanılan bir dildir. Tarihsel olarak, ML dalının dilleri her zaman resmi ispat sistemleri alanıyla yakından bağlantılı olmuştur ( Robin Milner'ın ilk ML'sinin bu nedenle LCF ispat sisteminde kullanıldığı ortaya çıktı). OCaml, alandaki en önemli yazılımlardan biri olan Coq prova asistanı tarafından kullanılan dildir .

OCaml Programlama dilleri ve derleyicilerin araştırma (bkz dahil bilgisayar bilimi araştırmalarının diğer birçok alanda, katılır Türetilmiş Diller bölümü ) veya Unison dosya senkronizasyon yazılımı .

sanayi

Nispeten çekingen iletişimine rağmen OCaml, endüstrinin belirli alanlarında sağlam bir kullanıcı tabanı oluşturmuştur. Bu nedenle havacılık endüstrisi, programlama güvenilirliği ve karmaşık algoritmaların formülasyonu için verimliliği için OCaml'i kullanır. Bu alanda, diğerlerinin yanı sıra Airbus şirketi tarafından kullanılan ASTRÉE projesinden bahsedebiliriz . Airbus aviyonik sistemleri veya belirli nükleer santrallerin kontrolü gibi kritik sistemler için kullanılan Lustre senkron gerçek zamanlı programlama dili derleyicisi de OCaml'de yazılmıştır.

OCaml , her ikisi de Caml Konsorsiyumu üyesi olan Microsoft veya XenSource gibi yazılım endüstrisindeki büyük oyuncular tarafından kullanılır . Ayrıca , birçok OCaml programcısı istihdam eden Jane Street şirketi veya finansa adanmış programlama dillerinin tasarımında uzmanlaşmış bir Fransız şirketi olan Lexifi tarafından gösterildiği gibi, finansal hesaplamada uygulamalar bulur ve ayrıca uluslararası olarak ödüllendirilir.

Son olarak, MLDonkey , GeneWeb , Liquidsoap web radyo istemcisi , FFTW kitaplığı gibi genel ücretsiz projeler ve KDE masaüstü ortamı için bazı yazılımlar tarafından da kullanılır . Son olarak, MediaWiki yazılımının matematiksel formülleri OCaml'de yazılmış bir program tarafından üretilir.

Dil sunumu

Bonjour Monde

Aşağıdaki merhaba.ml programını düşünün:

print_endline "Hello world!"

Bu derlenmiş olabilir yürütülebilir baytkoduna ile ocamlc bytecode derleyici:

$ ocamlc -o hello hello.ml

Ayrıca, yerel ocamlopt derleyicisi ile yürütülebilir optimize edilmiş yerel kodda derlenebilir:

$ ocamlopt -o hello hello.ml

Program daha sonra ocamlrun bayt kodu yorumlayıcısı tarafından yürütülebilir :

$ ./hello Hello world!

veya

$ ocamlrun hello Hello world!

Değişkenler

ocaml interaktif yorumlayıcı kullanılabilir. OCaml deyimlerinin girilebildiği, karakterlerle sonlandırıldığı bir "#" komut istemini başlatır ;;(bu ifade sonu karakterleri yalnızca etkileşimli yorumlayıcıda kullanılmalıdır, bunlar dil sözdiziminin bir parçası değildir). Örneğin x, hesaplamanın sonucunu içeren bir değişken tanımlamak için şunu 1 + 2 * 3yazarız:

$ ocaml # let x = 1 + 2 * 3;;

Bu ifadeyi girip doğruladıktan sonra, OCaml ifadenin türünü belirler (bu durumda bir tamsayıdır) ve hesaplamanın sonucunu görüntüler:

val x : int = 7

Her türlü hesaplamayı yapmak cazip gelebilir. Ancak, OCaml'de bunlar otomatik olarak dönüştürülmediğinden (bir tamsayı alıp gerçek bir değer döndüren bir işlev kullanmanız gerekir, ya da operatör tamsayıları kullanır). Aşağıdaki örnekte, + operatörü, bunlar iki gerçek olduğunda iki tamsayı eklemeyi umuyor:

# 2.3 + 1.;; Error: This expression has type float but an expression was expected of type int

Bu basit örnek, tür çıkarım algoritmasının nasıl çalıştığına dair ilk fikir verir. Nitekim yazarken 2.3 + 1.gerçek sayıları ekledik 2.3ve tamsayı 1.işleci ile bu +bir sorun teşkil ediyor. Aslında bu hesaplamayı yapabilmek için bir yanda tüm sayıların aynı tipte olduğundan emin olmamız gerekir (örneğin toplaması mümkün değildir 2.3ve 1çünkü 1bir tamsayı 1.veya 'den farklıdır 2.3) diğer yanda yasayı kullanmamız gerekir. OCaml'de +belirtilen +., gerçek sayılara uygulanan iç bileşimin . O halde şunu yazmalıydık:

# 2.3 +. 1.;; - : float = 3.3

Fonksiyonlar

Programlar genellikle prosedürler ve işlevler içinde yapılandırılmıştır. Prosedürler, programda birkaç kez kullanılan ve kolaylık sağlamak için aynı ad altında gruplandırılmış bir dizi komuttan oluşur. Bir prosedür bir değer döndürmez, bu rol fonksiyonlara atanır. Birçok dil (yeni bir prosedür ya da yeni bir fonksiyon tanıtmak için farklı anahtar kelimeler var prosedürü ve işlevini de Pascal , alt ve işlevi de Visual Basic ...). OCaml ise sadece fonksiyonlara sahiptir ve bunlar değişkenlerle aynı şekilde tanımlanır. Örneğin, kimliği tanımlamak için şunu yazabiliriz:

# let id x = x;;

İfadeyi girip doğruladıktan sonra, tip sentezi algoritması fonksiyonun tipini belirler. Ancak verdiğimiz örnekte hiçbir şey türünü tahmin etmez x, bu nedenle işlev polimorfik olarak görünür (kümenin herhangi bir öğesine, kümenin bir öğesi olan 'abir görüntüyü ilişkilendirir ): id x'a

val id : 'a -> 'a = <fun>

Bir işlevi çağırmak için aşağıdaki sözdizimini kullanırız:

# id 5;; - : int = 5

OCaml ayrıca anonim işlevlerin, yani bir tanımlayıcıya bağlı olmayan işlevlerin functionveya anahtar sözcüğü sayesinde kullanılmasına izin verir fun :

# function x -> x;; - : 'a -> 'a = <fun>

Anonim işlevler hemen çağrılabilir veya bir işlevi tanımlamak için kullanılabilir:

# (function x -> x + 1) 4;; - : int = 5 # let id = function x -> x;; val id : 'a -> 'a = <fun>

Desen filtreleme

OCaml'in güçlü bir özelliği de kalıp eşleştirmedir . Anahtar sözcüklerle match withveya anonim bir işlevle tanımlanabilir, ardından her desen için dikey bir çubuk |, desen, bir ok ->ve dönüş değeri gelir:

# let est_nul x = # match x with # | 0 -> true (* la première barre verticale est facultative *) # | _ -> false;; val est_nul : int -> bool = <fun> # function # | 0 -> true (* la première barre verticale est facultative *) # | _ -> false;; - : int -> bool = <fun>

Alt çizgi _, varsayılan düzeni temsil eder. Aynı değeri birkaç kalıba aynı anda vermek mümkündür:

# let contient_zero (x, y) = # match x, y with # | (0, _) | (_, 0) -> true # | _ -> false;; val contient_zero : int * int -> bool = <fun>

Anahtar kelime, whenkalıp üzerinde bir koşulu ifade etmek için kullanılır:

# let contient_zero (x, y) = # match x, y with # | (x, y) when (x = 0 || y = 0) -> true # | _ -> false;; val contient_zero : int * int -> bool = <fun>

Karakterler, karakter ..aralıklarını filtreleyen bir kalıbı ifade etmek için kullanılır:

# let est_capitale c = # match c with # | 'a'..'z' -> false # | 'A'..'Z' -> true # | _ -> failwith "lettre invalide";; val est_capitale : char -> bool = <fun>

Anahtar sözcük, asfiltrelenen değeri adlandırmak için kullanılır:

# let mettre_en_capitale c = # match c with # | 'a'..'z' as lettre -> Char.uppercase_ascii lettre # | 'A'..'Z' as lettre -> lettre # | _ -> failwith "lettre invalide";; val mettre_en_capitale : char -> char = <fun>

özyineleme

Yineleme tümevarım modeline, kendi belirtmektedir bir fonksiyon yazmak. OCaml'de özyinelemeli işlevler anahtar sözcüğü kullanılarak tanıtılır rec.

Örneğin, faktöriyel işlevi tanımlayabiliriz  :

# let rec fact n = # match n with # | 0 -> 1 # | _ -> n * fact (n - 1);; val fact : int -> int = <fun>

Fibonacci dizisini şu şekilde tanımlayabiliriz :

# let rec fib n = # match n with # | 0 -> 0 # | 1 -> 1 # | _ -> fib (n - 1) + fib (n - 2);; val fib : int -> int = <fun>

Dahili tanım

Anahtar kelimeyi kullanarak bir fonksiyon içindeki değişkenleri ve fonksiyonları tanımlamak mümkündür in.

Örneğin, faktöriyel işlevi tanımlayabiliriz:

# let fact n = # let rec fact_aux m a = # match m with # | 0 -> a # | _ -> fact_aux (m - 1) (m * a) # in fact_aux n 1;; val fact : int -> int = <fun>

Fibonacci dizisini şu şekilde tanımlayabiliriz:

# 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;; val fib : int -> int = <fun>

Terminal özyineleme

OCaml derleyicisi uçbirim çağrılarını optimize eder: bir fonksiyonun değerlendirilmesi sırasında gerçekleştirilecek son adım bir (başka) fonksiyonun çağrısı olduğunda, OCaml çağrıyı hafızada tutmadan doğrudan bu yeni fonksiyona atlar. şimdi işe yaramaz.

Özellikle, OCaml, terminal özyinelemeyi optimize eder . Örneğin, factyukarıdaki ikinci işlev (bir yardımcı parametre ile a), bir döngüye eşdeğer olan bir terminal işlevidir ve eşdeğer bir sonuç üretecek, böylece karşılık gelen zorunlu kodun performansıyla eşleşecektir.

Terminal özyineleme, yineleme kadar verimlidir; bu nedenle, daha net veya kullanımı daha kolay programlar yazmanıza izin verdiğinde tercih edilir.

Listeleri Manipüle Etme

Listeleri özellikle özyinelemeli işleme için, programlama kullanılır. Bir listenin öğelerinin tümü aynı türe sahiptir. Bir liste oluşturmak için, biri zincirleme operatörü ::ve diğeri operatör ile olmak üzere iki yazı mümkündür ; :

# 1 :: 2 :: 3 :: [];; - : int list = [1; 2; 3] # [1; 2; 3];; - : int list = [1; 2; 3]

::Bir ifadenin son zincirleme operatörünün sağ işleneni bir liste olmalıdır:

# 1 :: 2 :: 3 :: [4; 5];; - : int list = [1; 2; 3; 4; 5]

Birleştirme operatörü ile listeleri birleştirmek mümkündür @ :

# [1; 2; 3] @ [4; 5];; - : int list = [1; 2; 3; 4; 5]

List.lengthBu amaçla tanımlanan fonksiyonu kullanmadan bir listenin uzunluğunu bulmak için şunu yazabiliriz:

# let rec longueur l = # match l with # | [] -> 0 # | _ :: q -> 1 + longueur q;; val longueur : 'a list -> int = <fun>

Bu işlevi tür çıkarım algoritmasıyla analiz ederken, listenin herhangi bir veri türünü içerebileceği görülüyor 'a.

Aşağıdaki işlev, iki listeden bir çift listesi oluşturur: bu listenin uzunluğu, parametrede iletilen en kısa listenin uzunluğuna eşit olacaktır.

# let rec couple l1 l2 = # match l1, l2 with # | ([], _) | (_, []) -> [] # | (t1 :: q1, t2 :: q2) -> (t1, t2) :: couple q1 q2;; val couple : 'a list -> 'b list -> ('a * 'b) list = <fun>

Aşağıdaki işlev, bir listenin ilk öğesini alır:

# let premier_element l = # match l with # | [] -> failwith "liste vide" # | e :: _ -> e;; val premier_element : 'a list -> 'a = <fun>

Aşağıdaki işlev, bir listenin ikinci öğesini alır:

# let deuxieme_element l = # match l with # | [] -> failwith "liste vide" # | [_] -> failwith "liste à un élément" # | _ :: e :: _ -> e;; val deuxieme_element : 'a list -> 'a = <fun>

Aşağıdaki işlev, ilk alt listenin ilk öğesini alır:

# let sous_premier_element l = # match l with # | [] -> failwith "liste vide" # | [] :: _ -> failwith "sous liste vide" # | (e :: _) :: _ -> e;; val sous_premier_element : 'a list list -> 'a = <fun>

Daha yüksek dereceli fonksiyonlar

Üst düzey işlevler, girişte bir veya daha fazla işlevi alan ve / veya bir işlev döndüren işlevlerdir (buna işlevsel denir). Çoğu işlevsel dil, daha yüksek dereceli işlevlere sahiptir. OCaml ile ilgili olarak, bir önceden tanımlanmış modüller fonksiyonlarda örnekler bulabilirsiniz Array, Listvs. Örneğin, aşağıdaki ifade:

# List.map (function i -> i * i) [0; 1; 2; 3; 4; 5];; - : int list = [0; 1; 4; 9; 16; 25]

İşlev map, kendi bütünü iile karesini ilişkilendiren ve onu listenin öğelerine uygulayan anonim işlevi argüman olarak alır ve böylece kare değerlerinin listesini oluşturur.

Başka bir örnek :

# let double f i = f (f i);; val double : ('a -> 'a) -> 'a -> 'a = <fun>

Fonksiyon doublebir fonksiyon alır fparametre olarak ve bir değer ive iki kez uygulanır fiçin i.

# let trois = double (function i -> i + 1) 1;; val trois : int = 3 # let augmente_2 = double (function i -> i + 1);; val augmente_2 : int -> int = <fun> # let liste = # double ( # function # | [] -> [] # | e :: l -> (e + 1) :: l # ) [1; 2; 3];; val liste : int list = [3; 2; 3]

İşte bir örnek daha:

# let rec parcours f e l = # match l with # | [] -> e # | t :: q -> f t (parcours f e q);; val parcours : ('a -> 'b -> 'b) -> 'b -> 'a list -> 'b = <fun> # (* somme des éléments de la liste [1; 1; 2] *) # parcours (+) 0 [1; 1; 2];; - : int = 4 # (* fonction calculant la somme des éléments d'une liste *) # let somme_liste = parcours (+) 0;; val somme_liste : int list -> int = <fun> # (* fonction calculant le produit des éléments d'une liste *) # let produit_liste = parcours ( *. ) 1.;; val produit_liste : float list -> float = <fun>

Son olarak, son bir örnek. Burada, yeni bir not edilmiş operatör tanımlamaktan sorumluyuz $. Bu operatör iki işlevin birleşimini gerçekleştirir.

# let ( $ ) f g = function x -> f (g x) val ( $ ) : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b = <fun> # let f x = x * x;; val f : int -> int = <fun> # let g x = x + 3;; val g : int -> int = <fun> # let h = f $ g;; val h : int -> int = <fun> # (* affiche 36 *) # print_int (h 3);;

Özyinelemeli ağaçlar ve türleri

Herhangi bir türden ikili ağaç tanımlamak için özyinelemeli bir tür kullanırız. Bu nedenle aşağıdaki yazıya başvurabiliriz:

# type 'a arbre = # | Feuille # | Branche of 'a arbre * 'a * 'a arbre;; type 'a arbre = Feuille | Branche of 'a arbre * 'a * 'a arbre

Bu ağaç, istenildiği gibi dallanan ve yapraklarla sonlanan dallardan oluşur. Bir ağacın yüksekliğini bilmek için şunu kullanırız:

# let rec hauteur = # function # | Feuille -> 0 # | Branche (gauche, _, droite) -> 1 + max (hauteur gauche) (hauteur droite);; val hauteur : 'a arbre -> int = <fun>

İkiliğe göre kök arama

# let rec dicho f min max eps = # let fmin = f min and fmax = f max in # if fmin *. fmax > 0. then failwith "Aucune racine" # else if max -. min < eps then (min, max) (* retourne un intervalle *) # else let mil = (min +. max)/.2. in # if (f mil) *. fmin < 0. then dicho f min mil eps # else dicho f mil max eps;; val dicho : (float -> float) -> float -> float -> float -> float * float = <fun> (* approximation de la racine carrée de 2 *) # dicho (function x -> x *. x -. 2.) 0. 10. 0.000000001;; - : float * float = (1.4142135618, 1.41421356238)

hafızaya alma

Burada memoization kullanan bir fonksiyon örneği verilmiştir . Bu hesaplar bir fonksiyonudur n- th terimi Fibonacci dizisi . Klasik özyinelemeli işlevin aksine, bu, sonuçları ezberler ve hash tablosu sayesinde bunları sabit zamanda ortaya çıkarabilir.

(* Taille de la table de hachage. *) let _HASH_TABLE_SIZE = 997 (* Retourne le n-ième terme de la suite de Fibonacci. *) let rec fibo = (* Pré-définitions. Ce code est exécuté une fois lors de la définition de la fonction, mais ne l'est pas à chaque appel. Cependant, `h` reste dans l'environnement de cette fonction pour chaque appel. *) let h = Hashtbl.create _HASH_TABLE_SIZE in (* Premiers termes. *) Hashtbl.add h 0 0; Hashtbl.add h 1 1; function | n when n < 0 -> invalid_arg "fibo" (* Pas de nombre négatif. *) | n -> try Hashtbl.find h n (* On a déjà calculé `fibo n`, on ressort donc le résultat stocké dans la table `h`. *) with Not_found -> (* Si l'élément n'est pas trouvé, … *) let r = fibo (n - 1) + fibo (n - 2) in (* … on le calcule, … *) Hashtbl.add h n r; (* … on le stocke, … *) r (* … et on renvoie la valeur. *)

Bir polinomun türetilmesi

Burada, herhangi bir dereceden bir polinom türetmeye izin veren basit bir fonksiyon gerçekleştirmeyi öneriyoruz. Önce polinomumuzu temsil edecek türü belirtmeliyiz:

# type polyn = # | Num of float (* constante *) # | Var of string (* variable *) # | Neg of polyn (* négation *) # | Add of polyn * polyn (* addition *) # | Sub of polyn * polyn (* soustraction *) # | Mul of polyn * polyn (* multiplication *) # | Div of polyn * polyn (* division *) # | Pow of polyn * int;; (* exponentiation *) type polyn = Num of float | Var of string | Neg of polyn | Add of polyn * polyn | Sub of polyn * polyn | Mul of polyn * polyn | Div of polyn * polyn | Pow of polyn * int

Şimdi, parametrede belirtilen x değişkenine göre bu polinomu türeten fonksiyon.

# let rec deriv x = function # | Num _ -> Num 0. # | Var y when y = x -> Num 1. # | Var _ -> Num 0. # | Neg p -> Neg (deriv x p) (* -p' *) # | Add (p, q) -> Add (deriv x p, deriv x q) (* p' + q' *) # | Sub (p, q) -> Sub (deriv x p, deriv x q) (* p' - q' *) # | Mul (p, q) -> Add (Mul (deriv x p, q), Mul (p, deriv x q)) (* p'q + pq' *) # | Div (p, q) -> Div (Sub (Mul (deriv x p, q), Mul (p, deriv x q)), Pow (q, 2)) (* (p'q - pq')/q^2 *) # | Pow (p, 0) -> Num 0. # | Pow (p, 1) -> deriv x p # | Pow (p, n) -> Mul (Num (float_of_int n), Mul (deriv x p, Pow (p, n - 1))) (* n * p' * p^(n - 1) *) val deriv : string -> polyn -> polyn = <fun>

Farklı derleme hedefleri

OCaml uygulaması, diğer yazarlar tarafından bayt kodu ve yerel kod dışındaki derleme hedefleri için uyarlanmıştır . Bulacağız :

  • OCaml-Java, JVM için ocamlc, ocamlrun, ocamldep, ocamldoc, ocamllex, menhir, JVM için bir ocamljava derleyicisi içeren bir JVM dağıtımı;
  • OCamIL, .NET ortamı için bir arka uç prototipi . OCaml bayt kodu için bir derleyici (ocamlrun tarafından çalıştırılabilir), .NET için bir derleyici ve ocamlyacc gibi ocamilyacc adlı bir araç içerir.

türetilmiş diller

Birçok dil, OCaml'i ona işlevsellik eklemek için genişletir.

  • F # , Microsoft Research tarafından geliştirilen, OCaml tabanlı (ve kısmen uyumlu) bir .NET platformunun dilidir.
  • MetaOCaml , çalışma zamanına OCaml'e metaprogramlama işlevselliği getiren bir teklif ve kod oluşturma mekanizması ekler .
  • Fresh OCaml (OCaml'in başka bir türevi olan AlphaCaml'e dayalıdır) sembolik adları değiştirmeyi kolaylaştırır.
  • JoCaml, Eşzamanlı veya dağıtılmış programlara yönelik Join Calculus için OCaml desteğine ekler.
  • OcamlP3L, “ iskelet programlamaya” dayalı özel bir paralellik biçimi getiriyor .
  • GCaml, OCaml'e geçici polimorfizm ekleyerek , yazma bilgilerini koruyarak operatörün aşırı yüklenmesine veya sıralamaya izin verir .
  • OCamlDuce, tür sisteminin XML değerlerini temsil etmesine veya normal ifadelerle ilgili olmasına izin verir. OCaml ve Cduce dili arasında, XML'in işlenmesinde uzmanlaşmış bir aracıdır.
  • Opa , OCaml'de uygulanan ve çekirdeği OCaml dilinin işlevlerini içeren web uygulamalarının ve hizmetlerinin geliştirilmesi için bir dildir. Ayrıca Opa derleyicisi, yerel sunucular oluşturmak için OCaml derleyicisinin arka ucunu kullanır.
  • Facebook tarafından geliştirilen ReasonML, OCaml derleyicisini kullanan ve Reason (.re) ve OCaml (.ml) kodunun JavaScript kaynak kodunda (.js) derlenmesine izin veren bir dildir. web tarayıcısı veya Node.js gibi bir yorumlayıcı aracılığıyla.

Notlar ve referanslar

  1. "  Messenger.com Artık %50 Reason'a Dönüştürüldü · Reason  " , Reasonml.github.io adresinde ( 27 Şubat 2018'de erişildi )
  2. OCaml: SLAM'in bazı başarıları
  3. "Fonksiyonel programlar genellikle çok şey tahsis eden programlardır ve bir çok değerin çok kısa ömürlü olduğunu görüyoruz." Öte yandan, bir değer birkaç GC'den sağ çıktığı anda, uzun bir süre var olma şansı yüksektir ”- Objective Caml ile uygulama geliştirme
  4. Verimli makine kodu oluşturmak, OCaml'in her zaman önemli bir yönü olmuştur ve OCaml geliştirmenin başlangıcında (95-97) bunun üzerinde epeyce çalıştım. Günümüzde üretilen kodun performansından büyük ölçüde memnunuz.  »- Xavier Leroy, üzerinde caml posta listesine .
  5. Tip sistemi tarafından sağlanan garantiler, güçlü program optimizasyonlarını da sağlayabilir.  »- Xavier Leroy, Derleme türlerine giriş .
  6. (tr) posta listesi ileti dizisi  : "  Kapsamlı performans bildirimimiz" OCaml düzgün bir C derleyicisinin performansının en az %50'sini sağlar "geçersiz kılınmaz  :-)"
  7. (tr) çatışmada: OCaml vs. C kriteri .
  8. ocamlopt ve C# Mono arasındaki performans karşılaştırması .
  9. "  27 Kasım 2017 tarihli ESRS1732186N Muhtırası  "
  10. Caml ile programlama öğretmek
  11. Citeseer: Caml kullanan araştırma makalelerinin listesi
  12. www.astree.ens.fr adresindeki ASTRÉE projesinin sitesi15 Ocak 2011
  13. "Özet yorumlama: A380 yazılımına uygulama" , Patrick Cousot, www.di.ens.fr adresinde danışıldı.15 Ocak 2011
  14. Caml Konsorsiyumu
  15. Hızlı bir Fourier dönüşümü gerçekleştiren FFTW kitaplığı, C dilindeki kodlardan oluşur . Ancak, performans nedenleriyle, C kodu, OCaml'de yazılmış bir derleyici olan genfft tarafından otomatik olarak oluşturulur ve optimize edilir . Rutinleri oluşturma ve uzmanlaştırma süreci Matteo Frigo (MIT) tarafından yazılan A Fast Fourier Transform Compiler makalesinde [ çevrimiçi okuyun  (sayfa 9 Aralık 2007'de incelendi)] . FFTW belgelerinde OCaml kullanımına ilişkin bir değerlendirme buluyoruz: “  genfft kod üreteçleri paketi, makine öğreniminin bir lehçesi olan Objective Caml kullanılarak yazılmıştır. Objective Caml, Xavier Leroy tarafından geliştirilen küçük ve zarif bir dildir. Uygulama http://caml.inria.fr/ adresinde mevcuttur . FFTW'nin önceki sürümlerinde genfft, aynı yazarlar tarafından Caml Light ile yazılmıştır. Genfft bir daha da erken uygulama yazılmış Planı fakat Caml başvurunun bu tür için kesinlikle daha iyidir.  "- FFTW Teşekkür
  16. Kalzium yazılımının EqChem bileşen sayfası
  17. Uçbirim çağrılarını kullanan bir program, atlama modeli karmaşık olduğunda, genellikle eşdeğer bir yinelemeden daha okunabilirdir. Örneğin, bir otomat goto, otomatın diğer durumlarına terminal çağrıları (veya zorunlu dillerde atlamalar ) gerçekleştiren bir dizi geçiş işlevi olarak tanımlayabiliriz . Bu durumda, uçbirim çağrıları, Makrolar Üzerinden Otomatlar (içinde) makalesinde gösterildiği gibi daha fazla esneklik sağlar .

Şuna da bakın:

İlgili Makaleler

Dış bağlantılar