OCaml’ı neden ana dilim olarak seçtim
(xvw.lol)- OCaml’ın dil özellikleri ve ekosistemi mükemmeldir; hem kişisel hem de profesyonel projeler için uygundur
- Statik tip sistemi, cebirsel veri tipleri, modül sistemi, nesne modeli, kullanıcı tanımlı effect’ler gibi çoklu paradigma ve gelişmiş özellikler kararlı biçimde entegre edilmiştir
- OPAM paket yöneticisi, Dune derleme sistemi, LSP/Merlin editör desteği, Odoc dokümantasyon aracı gibi olgun bir araç zinciri vardır ve web, blokzincir, tooling gibi alanlarda çeşitli kütüphane ekosistemine sahiptir
- Topluluğu erişilebilirlik, samimiyet ve uzmanlık özellikleri taşır; bu da öğrenme ve iş birliğini kolaylaştırır ve istikrarlı evrim sayesinde gelecek görünümü de olumludur
OCaml’ı ana dil olarak seçme nedenim
- Yazar uzun süre boyunca çeşitli programlama dilleri kullandı ve bunların arasında OCaml’ı ana dili olarak seçti
- OCaml’ın en büyük avantajları arasında güçlü statik tip sistemi ve C ya da diğer fonksiyonel dillere kıyasla üstün fonksiyonel programlama desteği sayılıyor
- Söz konusu tip sistemi sayesinde birçok hata önleme ve kod optimizasyonu deneyimi yaşandı
- Gerçekten de çeşitli geliştirme projelerinde OCaml kullanarak üretkenlik ve kararlılık açısından büyük iyileşmeler elde edildi
OCaml’ın avantajları ve pratikte kullanımı
- Kodun büyük bölümü hızlı yazılabilir; fonksiyon bileşimi ve immutable veri kullanımı güvenliği artırır
- Son dönemde OCaml’ın ekosistemi ve araçları (IDE, build sistemi vb.) da sürekli gelişmektedir
- Çeşitli kütüphaneler ve harici paketler sayesinde iş ortamında verimli geliştirme mümkün hâle gelir
- Python ve Java ile karşılaştırıldığında OCaml daha az bilinir; ancak üretkenlik, güvenlik ve esneklik açısından çok güçlü bir seçenektir
Dilsel özellikler
- Araştırma kökeni ile endüstriyel uygulamanın birleşmesi, ifade gücü ve güvenlik odaklı özelliklerin gelişmesini sağlamıştır
- kullanıcı tanımlı effect’ler, affine session gibi modern özellikler
- Statik tip denetimi, bir güvenlik ağı ve tasarım aracı olarak işlev görür; zayıf tip deneyimlerinden kaynaklanan yanlış algıları ortadan kaldırır
- Çoklu paradigma: fonksiyonel, imperative, modüler, nesne yönelimli, multicore desteği
- ML ailesi sözdizimi kısa ve tutarlıdır; ReasonML gibi alternatif sözdizimleri de vardır
- Cebirsel veri tipleri (çarpım, toplam, üstel tipler), pattern matching ve polymorphism ile veri/alan modellemesinde güçlüdür
- Modül sistemi arayüz/uygulama ayrımı, soyutlama, yeniden kullanım ve gelişmiş polymorphism’e kadar destek sunar
- Bağımlılık tersine çevirme: modüller/effect’ler üzerinden esnek enjeksiyon yaklaşımı sağlar
Ekosistem ve tooling
- Derleme hedefleri: native, bytecode, JavaScript(
Js_of_ocaml,Melange), WebAssembly - MirageOS aracılığıyla çoklu bağlam kütüphaneleri yazmaya yönelik disiplin
- OCaml Platform:
- OPAM: sürüm yönetimi, switch’ler, paket indeksi, CI desteği
- Dune: hızlı derleme, S-expression yapılandırması,
dune-releaseile dağıtımı sadeleştirme - LSP/Merlin: VSCode, Emacs vb. üzerinde kod tamamlama, gezinme, biçimlendirme
- Odoc: çapraz referanslar, manuel sayfaları, doctest vb. desteği
- Zengin kütüphaneler: web (Dream, Ocsigen), blokzincir ve kriptografi (HACL*), test (alcotest, qcheck vb.)
- Standart kütüphane küçük olsa da Batteries, Base/Core, Containers gibi alternatifler vardır
Yeni meydan okumalar ve topluluk
- OCaml topluluğu küçük olsa da istikrarlı biçimde büyümekte ve kullanıcı dostu bir eğilim göstermektedir
- Yeni bir dil ya da paradigma konusunda meydan okuma arayan geliştiriciler için OCaml, derinlemesine öğrenmeye değer bir seçenektir
- Pek çok kullanıcı, OCaml deneyimi sayesinde yeni bakış açıları ve problem çözme becerilerinin arttığını belirtmektedir
Sonuç
- OCaml, belirli alanlarla (ör. finans, derleyiciler, sistem geliştirme) sınırlı kalmayıp genel amaçlı olarak kullanılabilen güçlü bir programlama dilidir
- Pratikte elde edilen verimlilik, bakım kolaylığı ve sorunları önleme yeteneği, gerçek iş ortamında onun değerini kanıtlar
- En yeni diller ya da trendlerle kıyaslandığında biraz daha az biliniyor olsa da, güvenilirlik ve güvenliğe önem veriliyorsa kesinlikle değerlendirmeye değer bir seçenektir
2 yorum
Bir ara yüksek lisansta OCaml ile uğraşmıştım ama ekosistemi gerçekten çok zayıf, referans da pek yok ve özellikle soru soracak kimse bulunmuyor. Kişisel ölçütlerime göre ülkemizde programlama dilleri camiası dışında kullanan neredeyse yok denecek kadar azdır. COBOL gibi şeyleri duymuş olsalar da OCaml'ı muhtemelen duymamışlardır..
Hacker News görüşleri
Google'da Rust'ın Android ekibine tanıtılması deneyimiyle ilgili bir sunum izlemiştim. Orada iki şey özellikle dikkatimi çekmişti: çeşitli projeler Python'dan Rust'a taşınmıştı, yani performans muhtemelen o kadar da büyük bir mesele değildi; ayrıca Rust kullanıcılarının en sevdiği özellikler pattern matching ve ADT'ler (Algebraic Data Types) gibi temel şeylerdi. Bu yüzden Rust'ın gerçekten büyük katkısının lifetime gibi kendine özgü özelliklerinden çok, 1990'lardaki ML dillerinin zaten sunduğu unsurlar olduğunu hissettim. Eğer OCaml 2010 civarında multicore gibi pürüzleri çözmüş olsaydı, bence Rust kadar popüler olabilirdi. Ne yazık ki OCaml akademi ile endüstri arasındaki boşlukta kaldı. Bir ek not olarak, 31 bit tamsayılar bit işlemlerinde pratikte can sıkıcı ve estetik açıdan da çift noktalı virgülü hiç sevmedim
Bence OCaml o dönemde zaten oldukça iyi durumdaydı. 2010'da profesyonel olarak Python'dan çok daha keyifli kullanıyordum. JaneStreet'in başardıklarına bakmak yeterli. OCaml'in yaygın biçimde benimsenmemesinin en büyük nedeni, ABD'de yapılmamış ya da oradan yönlendirilmemiş olması diye düşünüyorum. Bir dilin popülerliğinin teknik üstünlükten kaynaklandığına inanmak isteriz ama sonuçta mesele moda. Rust'ın kitlesel başarı kazanmasının nedeni de büyük ölçüde yoğun tanıtım ve aktif topluluk çalışmasıydı. Hatta buna adanmış çalışanları bile vardı
Google, gerçek servis kodunda kullanılabilecek resmi dil listesini olabildiğince kısa tutmaya çalışıyor. Rust'ın muhtemelen C++'ın yerini alabilecek ya da onu tamamlayabilecek bir dil olduğu için seçildiğini düşünüyorum. OCaml'in böyle bir konuma gelmesi zordu (Go'nun yerini alabilirdi ama olasılık düşüktü). Dolayısıyla Rust'ın seçilmesinin en büyük nedeni, ADT sunan resmi diller arasında tek seçenek olmasıydı; build hızını önemsememeleri değildi. OCaml'in Rust'ın yerini alamaması da gayet doğal. GC'li diller olarak zaten Go, Haskell vb. vardı ve 2010 civarında bare metal hedefleyebilecek kadar ifade gücü yüksek tek dil C++'tı (o da C++11 ve C++17 öncesinde daha kötüydü)
Kesinlikle katılıyorum. OCaml birkaç ufak sorunu çözebilseydi gerçekten önemli bir oyuncu olabilirdi. Build hızı bugün bile Rust'tan çok daha hızlı. Ama OPAM (paket yöneticisi) sık sık bug çıkarıyor ve kafa karıştırıcılığıyla ünlü. Windows desteği aşırı derecede kötü. Geçmişte Perl'ün Windows desteğinden bile daha kötü. Resmî dokümantasyon o kadar kısa ki neredeyse işe yaramaz. Söz dizimini anlamak da zor ve küçücük bir yazım hatası yüzünden dosyanın yarısının syntax error verdiği mesajlar görmek çok yaygın. Rust'ın mevcut C tarzı sözdizimi çok daha kolay. Özetle, OCaml'in avantajı hızlı build almak ama sadece bu da onu özellikle seçmek için yeterli değil
Bu yüzden ML tarzında programlama yapmak istediğimde Rust'tan önce Kotlin, Scala ve F#'a bakıyorum. Hatta bugünlerde Java ve C# bile yeterince çok ML özelliği benimsediği için bana çok yabancı gelmiyor. Caml Light ve Objective Caml günlerinden beri ML tip sistemine alışığım ama bugün insanların Rust'a bu kadar heyecan duymasını görünce sanki Rust ML tip sistemini yeni getirmiş gibi bir yanılgı oluşuyor
OCaml'in daha iyi hazırlanmış olmasını dilerdim görüşüne karşılık, aslında bence asıl büyük avantaj dil seçeneğinin bol olması. Sadece Birleşik Krallık'ta bile (nüfus az olsa da) çok farklı diller birlikte yaşıyor. Mesela Avrupa'nın ölü dillerinden Cornish bile son dönemde yerel halk tarafından canlandırıldı ve çobanlar arasında Kubrik diye sayma amaçlı bir dil de hâlâ var. Ben de gelecek nesiller için aile ağacımı tutmak adına OCAML tabanlı Geneweb adlı programı kullanmaya başladım (TMG adlı Windows uygulamasından geçtim). İçinde 140 bin kişi var. Geneweb'in OCAML ile yazılmış olması dile ilgimi artırdı. Programlama dilleri size zorsa, bir de soy ağacı/genealogy ile uğraşmayı deneyin derim. Yakında GEDCOM yüzünden başınız ağrımaya başlar
OCaml sevdiğim dillerden biri. En büyük işim, Writer's Festival organizasyonu için bir CRUD uygulamasını OCaml (ReasonML tabanlı JSX), Dream, HTMX ve DataTables ile %100 yapmak oldu. Modüller üzerinden frontend şablonlarını yeniden kullandım ve veri modelinde bir değişiklik olduğunda derleyicinin tam olarak nerede bozulduğunu göstermesinden çok memnundum. Excel verisini düzgün bir veritabanına taşımaktan .odt formatındaki takvim şablonlarını ya da sunucu diskine uğramadan doğrudan zip dosyaları üretmeye kadar, OCaml ekosisteminde şaşırtıcı derecede çok şey yapılabildi. Ama DB sorgularını tamamen string olarak yazmak ve tip dönüşümlerini elle yapmak zorunda kalmak inanılmaz yorucuydu (compile time type check yoktu). Kimlik doğrulama sistemini de kendim yazmak zorunda kaldım; yani asıl ürün geliştirme yerine çekirdek olmayan işlere gereğinden fazla zaman harcadım. Birçok dili dolaştıktan sonra vardığım sonuç şu: kusursuz dil yok. Her dilin kendine özgü eksileri var. Şu anda kendim için bir uygulamayı Rails ile yapıyorum; ihtiyacım olanların çoğu varsayılan olarak geliyor ve bu yüzden dilden çok gerçek layout tasarımı ya da fiilî deployment gibi asıl işlere odaklanabildiğim için daha memnunum
DarkLang önce OCaml ile geliştirildi, sonra F#'a geçti. Bunun başlıca nedeni kütüphane ekosistemi ve concurrency idi (ilgili yazı). .NET'e alışık olduğum için biraz önyargılı olabilirim ama sıkıcı kısımlar için bile pek çok hazır seçenek var ve bu da esas problemlere odaklanmayı kolaylaştırıyor. F#'ı profesyonel olarak epey kullandım, popüler bir UI kütüphanesini de sürdürüyorum, ama dil ekosistemi küçük olduğu için .NET dünyasında bile çözüm her zaman elinizin altında olmuyor. Bu yüzden ana akım dışı bir dil seçmenin (ör. C# yerine F#) bir maliyeti olduğunu akılda tutmak gerek. OCaml için de aynı durum geçerli; dil güçlü ama ana akım dışında olduğu için çeşitli sürtünmeler yaratıyor. Bazı şirketler bunu prod ortamında kullanıyor ama bunlar kendi özel ihtiyaçlarına göre şekillenmiş örnekler
Birkaç yıl boyunca OCaml'i sevmeye çalıştım ama en rahatsız edici yanı, "rastgele bir nesneyi print edememek" oldu. ppx ile otomatik
to_stringtüretilebiliyor ama ayarı uğraştırıcı ve Rust'a göre kullanım deneyimi daha zayıf.Set,Mapgibi tipleri yazdırmak için de ek iş gerekiyor (örnek tartışma). golang'de"%v"formatlamasıyla neredeyse her şeyi kolayca yazdırabiliyorsun ama OCaml bu açıdan daha fazla el işi istiyor%vformatlaması da kusursuz değil; pointer'ları daha derin dolaşmak için ayrıca go-spew gibi bir kütüphane gerekiyor. Python'ın__repr__yaklaşımı, şimdiye kadar gördüklerim arasında en rahatıOCaml'i doğrudan kullanmadım ama F# ile çalışmak çok keyifliydi. Bugünkü LLM çağında fonksiyonel dillere yeniden bakmak iyi olabilir diye düşünüyorum. OCaml ve Haskell gibi fonksiyonel paradigmada bilgiyi daha küçük bir metne verimli biçimde sıkıştırmak mümkün olduğundan, belki LLM'in context window'una da daha fazla anlam sığdırılabilir. Java, C# ve Ruby'ye kıyasla daha karmaşık değişiklikler bile tek seferde uygulanabilir; denemeye değer
Ben de başta öyle sanmıştım ama büyük bir Haskell kod tabanında çalışınca fikrim değişti. Eğitim veri setlerinde FP az olduğu için mi bilmiyorum ama daha özlü diller LLM'lere pek uymuyor gibi. Kod verbose olduğunda, LLM yanlış token tahmin ettikten sonra kendini düzeltmek için daha çok fırsat buluyor ve sanki daha doğru kod üretiyor
Kendi küçük deneyimde C++ ve Haskell ile basit bir CLI oyunu yaptım; satır sayısı Haskell'de daha azdı ama kelime sayısı neredeyse aynıydı, yani sadece kod daha "geniş" görünüyordu. Java ya da daha açık yazılan dillerle karşılaştırmadım ama bence hangi stilin uygun olduğu programın doğasına bağlı. Bazı şeylerde imperatif stil, bazılarında ise fonksiyonel stil daha uygun olabilir
LLM'lerin kod üretme becerisi biraz daha gelişirse, çok güçlü tip sistemleri ve effect sistemleriyle kodun davranış alanını sınırlayabilmek harika olurdu. Mesela dependent types varsa, "bu fonksiyon mutlaka sıralanmış bir liste döndürür" ya da "bu fonksiyon mutlaka geçerli bir Sudoku çözümü döndürür" gibi koşullar compile time'da doğrulanabilir. Buna bir de effect sistemi eklenirse, "bu fonksiyon geçerli bir Sudoku çözümü döndürür ama ne ağa ne de dosya sistemine erişir" demek de mümkün olur. LLM'ler daha da gelişirse belki bunların benzerini Python'da da yapabilirler ama ilerleme yavaş kalırsa, güvenilir olmayan LLM'leri güvenilir deterministik sistemlerle çevreleyip kullanmak geleceğin yönü olabilir
Scala'da cats-effect (effect kütüphanesi) kullanırken LLM yardımıyla geliştirme hızım inanılmaz arttı. cats-effect kodu, basit kavramlarda bile gereksiz zorlayıcı hissettirebiliyor ama LLM'e sadece "cats-effect'te şunu nasıl yaparım?" diye sormak çoğu zaman %80 oranında hemen çözüm veriyor. Kalan %20 için biraz daha bağlam eklemek yetiyor. Bakım tarafında hâlâ deneme aşamasındayım ama effect tabanlı fonksiyonel programlamanın yarattığı hayal kırıklığı ciddi biçimde azaldı. Bir dahaki sefere Claude Code'un bunu ne kadar iyi yaptığını denemek istiyorum
Haskell'in LLM ile kod üretiminde iki büyük avantajı var. Birincisi, ifade gücü yüksek tip sistemi pek çok hatayı yakalıyor; ortaya çıkan derleme hatalarını tekrar LLM'e geri bildirim olarak verebiliyorsun. İkincisi, property-based testler (QuickCheck vb.) sayesinde kodu verimli ve doğru biçimde iyileştirmek kolay. LLM testleri kendi başına çok iyi yazamıyor ama siz eklediğinizde üretilen koddaki bug'ları hızlıca buluyor
Bu yazıyı görünce "Neden F# yerine OCaml kullanayım ki?" sorusuna noktayı koydum. Neredeyse her OCaml başlığında birileri çıkıp "F# kullansan araç sorunları çözülmez mi?" diyor. Ben de OCaml'i merak ediyordum ve "Go with types" lakabını gördüğüm için ilgimi çekmişti ama OCaml'in kendisi henüz bana tamamen cazip gelmiyor. Erlang, Ruby, Rust ve Zig gibi diğer dil topluluklarındaki tutkuya benzemeyen bir havası var
Ben tam tersine F# araç ekosisteminden kaçıp OCaml'e geçmiş biriyim. F# kullandığım dönemde derleyici yavaştı; ekosistem C#'a odaklıydı; MSBuild zayıftı ve dokümantasyonu da kötüydü; Ionide sürekli çöküyordu; Fantomas da güvenilir değildi. Tabii OCaml de F#'ın performans odaklı özelliklerinin hepsinin yerini tutmuyor (ör. value type'lar gibi CLR'ın desteklediği şeyler). Bu yüzden hâlâ basit bir ML ailesi dili bulabilmiş değilim. Belki ileride OxCaml vb. bunu çözer diye umut ediyorum
Son zamanlarda OCaml'i çok kullanmıyorum ama dilin özü hâlâ en sevdiğim çekirdeklerden biri. Kod yazma stilim devasa tek bir fonksiyona kayma eğiliminde ama OCaml bunu doğal biçimde engelliyor. Yan projelerde Rust kullanıyorum ama dürüst olmak gerekirse OCaml daha rahat. Bu yüzden F#'ı da mutlaka bir ara denemek istiyorum
Terminolojiyle ilgili bir sorum var: yazıda fonksiyon tipleri için "üstel tipler (exponential types)" deniyor ama higher-order function tiplerine neden böyle dendiğini tam anlamadım
Zaten iyi bir açıklama verilmiş ama daha derindeki neden şu: fonksiyon tipleri cebirsel olarak üs kurallarına uyuyor. Örneğin
A → (B → C), currying sayesinde(A × B) → Cile izomorfiktir. Bu da(cᵇ)ᵃ = cᵇ˙ᵃkuralına benzer. Ayrıca(A + B) → C,(A → C) × (B → C)ile izomorfiktir; bu dacᵃ⁺ᵇ = cᵃ·cᵇkuralına karşılık gelirBirinci dereceden fonksiyon tipleri de zaten üstel. Mesela bir sum type, case sayısı kadar değere sahiptir. (
A of bool | B of bool→2+2=4olası değer). Product type'lar ve exponential type'lar da aynı şekilde.bool -> booldersen2^2 = 4olası değer vardır (yan etkileri saymazsan)Genelde ADT (Algebraic Data Type) konuşurken sadece sum ve product ele alınıyor. Fonksiyonlar veri olmadığı için çok anılmıyor. Ama
a -> btipib^akadar olasılığa sahip olduğundan aynı şekilde ele alınabilirBenim de aynı sorum vardı ama matematikte toplama (sum), çarpma (product) sonrası üs (exponent) geldiği için mecazi olarak böyle deniyor sanıyordum
Yanıtların hepsi doğru ama aslında category theory'de fonksiyon tipine "exponential product" deniyor. Bu ad da A'dan B'ye fonksiyon sayısının, B'nin kardinalitesi üzeri A'nın kardinalitesi olarak hesaplanmasından geliyor
sum type'ın case'leri, type constructor üzerinden kurulan değerler (expression) olduğundan elbette tip taşırlar. Örneğin,
her bir case'in bir tipi vardır. Pattern matching sayesinde type constructor parametrelerini zaten doğrudan unpack ediyorsun. Case'leri ayrı tiplere bölmek, sum type'ın sunduğu exhaustiveness avantajını kaybettirir ve hatta yanlış program durumlarını ifade etmeyi mümkün kılar. Sum type'lar bir kez tanımlanır, birçok kez kullanılır ve çoğu zaman disposable yapıdadır. Kodun okunabilirliği de önemlidir; uzunluğun maliyeti bazen küçümseniyor. Bu arada C#/Java gerçek anlamda sum type desteklemiyor. Aşağıdaki örnekte C#'ın OOP yaklaşımı yüzünden gereksiz yere karmaşıklaştığını görebilirsin
ML'de ise çok daha kısa
İki yaklaşım neredeyse aynı ama C#'taki OOP unsurları burada ayak bağı oluyor
OCaml'de GADT, polymorphic variant vb. ile bunları ayrı tipler gibi de kullanabilirsin. Ama genel olarak sum type'ı bölmek hem genellemeyi zorlaştırır hem de anlamayı güçleştirir. Beraberinde type equality ve variance sorunları da gelir
Sum type ile sealed type tartışmasının neden bu kadar büyüdüğünü anlamıyorum. Fonksiyonel dilleri daha çok sevsem de, type level ayrım yapabildiğin sürece sealed type'larla da sum type'ların hepsi modellenebilir ve subtyping sayesinde tanım ve kullanım bazı yönlerden daha kolay olabilir. Sistemlerin paradigması çok farklı ama matematiksel olarak neredeyse denktirler; OOP ve FP tarafında yapılabilecek type oyunlarının çoğu da dilin izin verdiği ölçüde gerçekleştirilebilir
Java/Kotlin'deki sum type bildiriminin uzunluğunun buna değdiğine katılmıyorum. Bana daha çok JVM dillerinin tipik boilerplate yükü gibi geliyor
ReasonML sözdizimini bu kadar iyi bilen birinin artılarını ve eksilerini karşılaştırmasını isterdim. (Yazıda kısaca değinilmişti)
Benim en çok özlediğim şey let binding'lerdi (resmî doküman). ReasonML'de monad'lar için
>>=gibi operatörleri doğrudan özelleştirip rahat kullanabiliyordun. rescript'te (ReasonML'in fork'u) bu hâlâ yok. Onun yerineasync/awaitsözdizimi iyi destekleniyor; asenkron kodda işe yarıyor. Melange (yazıda kısaca geçiyor) ise Reason sözdiziminde let binding desteği veriyor. Bu yüzden React tabanlı frontend'de Melange'in Reason ML'i çok avantajlı. Let binding sayesinde (JSX ile birlikte) monadik tarzda asenkron kod da temiz yazılabiliyor. OCaml sözdiziminde bunu PPX ile dolanmak mümkün ama editörde syntax highlighting iyi çalışmıyor. Backend açısından bakınca, ben Python tarzını sevdiğim için süslü parantezler hâlâ gözüme batıyor ve fonksiyon çağrısı/tanımında parantezsiz yazmayı tercih ediyorum. Ama yeni bir OCaml kullanıcısı olarak, değişken olmayan argümanlar geçerken parantez kullanımı hâlâ kafamı karıştırıyor. Umarım bu deneyim faydalı olurReasonML'i pek kullanmadım, o yüzden avantajlarını hissetmedim. Tabii 4 yıl içinde iki kez ölmüş olması dışında...
Reason sözdiziminin daha yaygın olmasını isterdim ama OCaml topluluğuyla iletişim kurmak için standart sözdizimini öğrenmek daha mantıklı. Kodların ve dokümanların çoğu standart sözdiziminde, yani eninde sonunda bilmek gerekiyor
Benim yaşadığım ReasonML deneyiminde en can sıkıcı şey LSP'nin düzgün çalışmamasıydı
dependency injection'ın effect system ile nasıl uygulandığını daha ayrıntılı anlatmalarını isterdim. Pattern matching ile test/prod değerlerini bağlama fikri ilginç görünüyor ama yazıdan tam oturtamadım. Ayrıca module system'in kendi tip sistemine sahip olduğunu ilk kez duydum, o da çok ilginç geldi