1 puan yazan GN⁺ 2024-11-14 | 1 yorum | WhatsApp'ta paylaş
  • Raku, yüksek olgunlukta tek bir tasarımdan çok, birden fazla fikri doğrudan denediği bir dil özellikleri laboratuvarına daha yakın; başka dillerin benimseyebileceği deneyleri tek yerde görmeyi sağlıyor
  • Junctions, olası değerler kümesine işlemleri yaydıktan sonra all, any, one gibi Boole nicelik belirleyicileriyle katlayarak karmaşık koşulları kısa ifade ediyor
  • Whatevers içindeki *, sonsuz aralıklar, anonim fonksiyonlar ve liste uzunluğuna dayalı indeksleme için kullanılıyor; kısa ama alışılmadık bir kod tarzı oluşturuyor
  • Raku regex’leri, PCRE uyumluluğundan vazgeçmek karşılığında birleştirilebilir gramerler, değer ayırıcıları, okunabilir lookahead ve varsayılan olarak boşlukları yok sayma gibi kolaylıklar sunuyor
  • Hyperoperators, Pair Syntax, Slangs, RakuAST ve Rakudo Star’a bakıldığında Raku’nun sözdizimi deneylerinden dağıtım biçimine kadar geniş bir alanda denemeler yapan bir dil olduğu görülüyor

Raku’nun neden bir dil özellikleri laboratuvarı gibi göründüğü

  • Raku’yu bir yıldan uzun süre fiilen kullandıktan sonra, Raku “dil özellikleri için bir laboratuvar”a daha yakın bir dil gibi görünüyor
  • Beş farklı eşzamanlılık modeli ve aynı işi yapmanın birden çok yolu, “ne olacağını görmek için” yapılan deney niteliğini ortaya koyuyor
  • Birçok özelliğin tuhaf biçimde etkileşime girmesinin ve çok sayıda edge case barındırmasının nedeni de, 100 deneyi çalıştırmaktan çok onları cilalayıp birlikte çalışır hâle getirmenin çok daha zor olması
  • Burada ele alınan özellikler, başka programlama dillerinde de bir gün görülebilecek Raku tarzı deneyler

Junctions: olası değerlerin üst üste bindirilmesi ve Boole nicelik belirleyicileri

  • Junctions, olası değerlerin üst üste bindirilmesini temsil eder; bir junction’a işlem uygulandığında aynı işlem içerideki tüm değerlere uygulanır
    • 2|10, any(2, 10) olur
    • 2&10 + 3, all(5, 13) olur
    • (1&2) + (10^20), all(one(11, 21), one(12, 22)) gibi birleşir
  • Junctions’ın temel kullanım amacı all, any gibi Boole formüllerini ifade etmektir
    • Bir junction’ı destructure etmenin bir yolu yoktur
    • Pratikte kullanmak için önce Boole değerine katlamak gerekir
  • so, junction’ı Boole değerine zorla dönüştürür
    • so (1&2) + (10^20) < 15, True döner
    • so (1&2) + (10^20) > 0, False döner
  • Raku’daki list.all, argüman alan bir metot değil, listeyi junction’a çeviren argümansız bir metottur
    • <1 2 3>.all, all(1, 2, 3) olur
    • is-prime($x) uygulandığında her değere uygulanarak all(False, True, True) gibi olur
  • Junctions birleştirilerek unique benzeri davranışlar da oluşturulabilir
    • “Her eleman tam olarak bir elemanla eşit mi?” ifadesi {.all == .one} ile anlatılabilir
    • <1 2 3 7> doğru, <1 2 3 7 2> ise yanlış olur

Whatevers: * ile oluşturulan sonsuz aralıklar ve anonim fonksiyonlar

  • Whatevers içindeki *, Raku’da birden çok rol üstlenen whatever sembolüdür
  • Aralıklarda veya dizilerde *, sınır olmadığını ifade eder
    • 1..*, 1..Inf anlamına gelir
    • (2,4,8...*)[17], 262144 döner
  • * içeren ifadeler anonim fonksiyona yükseltilir
    • Bu davranışa whatever-priming denir
    • Sonuç WhateverCode olur ve tipi dışında diğer fonksiyonlardan ayırt edilmez
    • (* + 10)(2), 12 döner
    • (^10).map(* % 2), 0 1 0 1 ... desenini oluşturur
  • Bir ifadede iki * varsa her biri ayrı bir konumsal argüman olur
    • (2, 30, 4, 50).map(* + *), (32, 54) döndürür
    • Bu davranış zorlu Fibonacci tanımları için faydalıdır, ancak her *ın aynı değer olduğu yaklaşımdan daha iyi olduğundan emin değilim
  • Raku metotlarının önemli bir kısmı fonksiyon alabildiği için priming yaygın kullanılır
    • l[*-1] negatif indeks gibi görünür, ama aslında [] liste uzunluğunu fonksiyona geçirip hesaplanan indeksi sorgular
    • Listenin uzunluğu 10 ise l[*-1], l[10-1], yani son eleman olur
    • l.head(2) ilk iki elemanı, l.head(*-2) ise son iki eleman hariç tümünü ifade eder
  • [] içine başka fonksiyonlar geçirilirse ring buffer gibi yapılar da kolayca uygulanabilir
    • @x[95 % *]--, liste uzunluğunu kullanarak konumu hesaplar

Regex: PCRE uyumluluğunu bırakıp birleştirilebilir gramerlere geçmek

  • Raku, POSIX regex veya PCRE’den farklı yeni bir regex sözdizimi kullanır
    • POSIX regex, çok sayıda ters eğik çizgi ve noktalama işareti içeren bir yapıdır
    • PCRE, POSIX ile geriye dönük uyumludur ve daha karmaşık ters eğik çizgi/noktalama yapısını devralır
    • Perl 6, geriye dönük uyumluluğu kırarak yeni bir regex sözdizimi getirdi
  • En belirgin iyileştirme birleştirilebilirlik tarafındadır
    • Birçok dilde regex string’leri yan yana eklenerek birleştirilir
    • Raku, /< foo >+/ gibi başka bir regex’i içeri yerleştirerek foo regex’ini bir veya daha fazla kez eşleştirir ve bunun üst regex’e sızmamasını sağlar
  • Karmaşık regex’ler daha küçük ve okunabilir parçalara bölünebilir
    • Bu yaklaşım, Raku’nun parsing gramerlerini yerleşik dil özelliği olarak desteklemesinin temelini oluşturur
  • Geriye dönük uyumluluğu kırarken çeşitli kolaylık özellikleri de eklendi
    • \d+ % ',', 1, 1,2, 1,1,4 ile eşleşir; ancak 1, veya 12 ile eşleşmez
    • lookahead ve non-capturing group anlaşılması zor sembol kombinasyonları değildir
    • r1 && r2, yalnızca hem r1 hem r2 koşulunu karşılayan string’lerle eşleşir
    • : ile backtracking durdurulabilir
    • Boşluklar varsayılan olarak yok sayılır; eşleşme deseninde açıkça etkinleştirilmeleri gerekir
  • Raku’nun regex notasyonu, gerçek işleme yeteneklerinden bağımsız olarak başka dillerde de ortaya çıkabilecek bir özellik olarak görülebilir

Hyperoperators: iç içe listelere kadar inen genelleştirilmiş mapping

  • Hyperoperators temel biçimi olan l>>.method, mape benzer ama alt listelerin içine özyinelemeli olarak iner
    • [1, [2, 3], 4]>>.succ, [2 [3 4] 5] olur
  • Raku’da f(list, *args) biçimindeki fonksiyon çağrısı, list.&f(* args) biçiminde metot formuna dönüştürülebilir
    • Bu yüzden >>. genelleştirilmiş bir mapping operatörü gibi çalışır
    • Whatever ile birlikte [1, [2, 3], 4]>>.&(*+1) şeklinde kullanılabilir
  • İkili hyperoperator olan l1 << op >> l2, opu iki listeye eleman bazında uygular
    • Daha kısa liste, uzun liste bitene kadar tekrarlanır
    • [1, 2, 3, 4, 5] <<+>> [10, 20], [11 22 13 24 15] olur
    • << op<< veya >>op>> biçimleri yalnızca sol ya da sağ liste bitene kadar tekrarlar
  • Tekil değerler ve iç içe listelerle de çalışır
    • [1, 2, 3, 4, 5] <<+>> 10, [11 12 13 14 15] olur
    • [1, [2, 3], 4, 5] <<+>> [10, 20], [11 [22 23] 14 25] olur
  • İki hash için hyperoperator, birleşim, kesişim ve hash farkına op uygulayan ayrı davranışlara da sahiptir
  • Hyperoperator adını, tüm işlemleri paralel değerlendirmesinden alır
    • Açık döngüler de hyper önekiyle paralelleştirilebilir

Pair Syntax: hash’in temel birimi ve kısa bayrak aktarımı

  • Pair, Raku hash’lerini oluşturan temel birimdir
    • Hash, key => value çiftlerinden oluşan bir koleksiyondur
    • Pair temel tiptir; hash ise pair koleksiyonudur
  • Raku’da pair’leri kısa belirtmek için çok sayıda colon syntax vardır
    • my $x = 3; :$x, x => 3 olur
    • :a<$x>, a => "$x" olur
    • :a($x), a => 3 olur
    • :3a, a => 3 olur
  • En önemli kısaltma :key ve :!key biçimleridir
    • Bunlar sırasıyla key => True, key => False olarak eşlenir
    • Metotlara bayrak eklemenin kısa bir yolu olarak kullanılır
  • match metodu, bayrak gibi birden fazla colon pair alır
    • :continue(:$c), :pos(:$p), :global(:$g), :overlap(:$ov) gibi biçimler kullanır
    • İmzadaki :f(:$foo), $foo parametresini tanımlarken :f takma adını da oluşturur
    • Çağıran taraf aynı bayrağı :f veya :foo ile ayarlayabilir
  • Colon pair argümanları sıra ve konum açısından esnektir
    • "abab".match(/../, :g), global eşleştirme yapar
    • "abab".match(/../, :g, :ov), örtüşmeli eşleştirme yapar
    • "abab".match(:g:ov, /../) gibi sıra değiştirilebilir ve bitişik yazılabilir
    • "abab".match(:g, /../):ov:2nd gibi fonksiyon çağrısından sonra anahtar sözcük argümanları konabilir
  • Bu sözdizimi, metot seçeneklerini match(global=True, overlap=True) yazmaktan çok daha kısa belirtmeyi sağlar

Slangs, RakuAST, Rakudo Star

  • Slangs, Raku sözdizimini değiştiren bir özelliktir
  • RakuAST, Raku ifadelerini Raku içinde AST olarak parse eden bir özelliktir
    • Q/my $x; $x++/.AST, değişken bildirimi ve postfix artırma işlemini RakuAST::StatementList biçiminde gösterir
    • Q/my $x; put $x/.AST.DEPARSE("NL") gibi, Raku kodunu başka bir dil tarzı notasyonla çıktılama örneği vardır
  • Raku’da Rakudo Star kurulum dağıtımı vardır
    • Bu dağıtım, seçili üçüncü taraf modülleri önceden kurulu olarak sunar
    • Büyük bir standart kütüphanenin bakım yükü ile kullanıcının ekosistemde uygun paketi kendi bulma yükü arasında bir uzlaşmaya yakındır

1 yorum

 
GN⁺ 2024-11-14
Hacker News yorumları
  • Daha önce burada bahsettiğim birleştirilebilir düzenli ifadeler özelliğine benzer bir şeyi JavaScript için bağımsız olarak uygulamıştım; aradan yıllar geçmesine rağmen başka projelere en sık taşıdığım kütüphanelerden biri hâlâ bu
    Dilin içinde birinci sınıf bir parser varmış hissine biraz daha yaklaşıyor; örnek olarak bunu kullanıp medya türü ayrıştırmayı düzenli ifadelerle gerçekleştiren bir uygulama var: https://runkit.com/tolmasky/media-type-parsing-with-template...
    npm’de templated-regular-expression, GitHub: https://github.com/tolmasky/templated-regular-expression
    Elbette programlama dillerinde gerçek parser’lar olmalı ve düzenli ifadeler parser olarak kullanılmamalı; ama zaten düzenli ifade kullanacaksanız, onu küçük parçalara bölebilmek gerçekten çok iyi

    • “Gerçek parser” Raku’yu ayrıştıracak kadar güçlü değil
      Raku’nun düzenli ifadeleri grammar ile birleşince çok daha güçlü oluyor ve iyi yazıldıklarında herhangi bir “gerçek parser”dan daha anlaşılır olabiliyor. Raku’yu sıradan bir parser ile ayrıştırmak için, ayrıştırma sırasında parser’a öğe ekleyip çıkarabilmeniz gerekir; Raku’nun parser’ı bunu, mevcut grammar’yi subclass edip geçerli sözcüksel kapsam içinde öğeler ekleyip çıkararak ve kapsam bitince önceki grammar’ye dönerek halleder
      Raku’da düzenli ifade, kod yazmak için kullanılan başka bir sözdizimidir; temel sözdizimi ve davranıştan yalnızca biraz farklıdır, ayrıca parametreleri ve değişkenleri olabilir. Düzenli ifade sözdiziminin uygun olmadığı bir iş varsa, normal Raku sözdizimini araya sokup gereken işi yaptıktan sonra tekrar düzenli ifade sözdizimine dönebilirsiniz
      Örneğin bir veya daha fazla A’nın ardından aynı sayıda B ve aynı sayıda C eşlemek de mümkündür; çoğu düzenli ifade sözdiziminde aynı sayıda A ve B eşlemek için arada özyineleme gerekir, ama bunu yapınca C’yi de aynı şekilde ele almak zorlaşır ve okunması çok daha güçleşir. Raku’nun yaklaşımı geri izleme ya da özyineleme gerektirmez, bu yüzden oldukça hızlı çalışabilir
      Grammar ile paketlediğinizde eksiksiz bir parse tree elde edersiniz; grammar olmadan da yapılabilir ama grammar kullanmak daha kolaydır. Gerçek parser örneği olarak sık sık JSON::TINY::Grammar önerilir: https://github.com/moritz/json/blob/master/lib/JSON/Tiny/Gra...
      Açıkçası “gerçek parser” tasarımının önemli bir kısmı, ilk bilgisayarların kısıtlı RAM’inden kaynaklanan bir yan ürün gibi görünüyor. Ayrı bir tokenization aşaması, kaynak kodun kapladığı RAM’i azaltıp sonraki anlamsal analiz ve derleme için bellek bırakmaya yönelikti; bunun sonraki aşamaları o kadar da çok basitleştirdiğini düşünmüyorum. Yukarıdaki JSON::Tiny modülü, grammar ayrıştırma yaparken action class aracılığıyla yerel Raku veri yapıları oluşturduğu için, ayrıştırırken aynı anda derleme yapmış oluyor
  • Raku’yu prodüksiyonda kullanıyorum. Metin işleme için en iyi dil ve parser oluşturma deneyimi inanılmaz iyi
    Bunun LLM metin pipeline’ları oluşturmak için en üst düzey dil olmaması şaşırtıcı

    • Geç katıldım ama Raku ile HTTPS API çağırıp belirli bir değer dönene kadar polling yapan iyi bir örnek biliyor musunuz merak ediyorum
    • Raku’nun LLM paketlerini kullanıyor musunuz; kullanıyorsanız hangilerini kullandığınızı merak ediyorum
  • Vay. Bir gün Raku codebase’i bakımını yapmak zorunda kalmadan sektörden ayrılmak istiyorum

    • İlginçtir, o blog yazısını okuyunca işimi bırakıp Raku ekibini bulup onlarla çalışmak istedim. Belki hâlâ fazla safımdır :)
    • Tipik Raku kodu görmediyseniz, yazıyı okuyup böyle tepki vermeniz anlaşılır
      Giriş seviyesi Raku kitaplarına bakınca birçok yerde Python’a C ailesi sözdizimi eklenmiş gibi hissettiriyor. Süslü parantez merkezli bir sözdizimi var ama kullanım kolaylığı, yerleşik veri yapıları ve nesne yönelimli özelliklerin hepsi üst seviye
      Başka üst seviye betik dillerini biliyorsanız, benzer bir betiğin Raku kodunu oldukça kolay okuyabileceğinizi düşünüyorum. Gündelik kodda gerçekten tuhaf özelliklerin çoğunu çoğu kişinin kullanacağını sanmıyorum; Raku daha esnek ama normal kod genellikle anlaşılması zor görünmüyor
    • Perl’e benziyor. Kimse bakımını yapmak istemiyor ama kullanması gerçekten çok eğlenceli. İfade gücü çok yüksek
      Raku’da keyword argument’ları kısaltılmış biçimde tanımlayabilme, örneğin :global(:$g) ya da True değeri varsayarak match(/foo/, :g) gibi global düzenli ifade eşleşmesi çağırabilme yeteneğinde de bunu görüyorsunuz. Perl’de de bunlardan çok var; hepsi daha hızlı ve eğlenceli kullanmak için, ama yeni başlayanlar için daha az okunabilir
    • İnsanların yapay zeka destekli yazılmış codebase’lerin bakımı için de benzer şeyler söylemesi tuhaf
      Sanırım bu artık bir nesil farkı olacak. Daha yaşlı programcı kuşağının tamamı, mevcut kuşak için sıradan olan çalışma ortamında yerini kaybetmiş gibi hissedebilir
    • Raku’nun “sektör” için tasarlanmış bir dil olduğunu düşünmüyorum
  • Bazı özellikler yarı tanıdık geliyor. Hyper, recursion-schemes tarafındaki bir şeyin daha doğaçlama yapılmış bir sürümü gibi geliyor; burada gösterilen * da Scala’daki _ ile bir ölçüde benzer
    _ lambda’larda kullanmak için çok hoşuma gidiyor; keşke tüm diller benzer bir şeyi benimsese

  • > (2, 30, 4, 50).map(* + *) returns (32, 45) aslında returns (32, 54) olmalı değil mi? İkinci terim 4+50 olurdu
    Belki de bazı ülkelerde İngilizcedeki fifty-four yerine vierenvijftig gibi “four and fifty” şeklinde söylenmesinden kaynaklanan bir ön ek çevirisi sonucudur

    • rakudo’da kontrol ettim; gerçekten de (32 54) döndürüyor. Yazarın eli kaymış gibi
  • O hâlde Perl artık APL ailesi dillerine giden bir giriş uyuşturucusu mu?

    • Evet. Üstelik yazıda meta operatörler de ele alınmamış
      Örneğin reduce meta operatörü [ ], infix + ile birlikte kullanılarak “hepsini topla” yapılabilir: [+] 1, 2, 3
  • Raku’da hız hâlâ büyük bir sorun. Regex ile günlük dosyalarını ayrıştırmak Perl’ün güçlü yanı, ama en güncel Raku bile başlangıç süresi hariç Python 3.13’ten 6,5 kat daha uzun sürüyor

    • Bununla birlikte örnek de sunulmalı. Benim deneyimime göre Raku’nun daha hızlı olduğu şeyler de var, daha yavaş olduğu şeyler de; bu yüzden neyde yavaş olduğuna bakmadan yalnızca “Raku Python 3.13’ten 6,5 kat daha uzun sürüyor” demek pek anlamlı değil
  • (2,4,8...*)[17] ifadesinin 262144 olması gerçekten şaşırtıcıydı

    • Benim aklıma hemen “korkunç” kelimesi geldi; ardından “korkunç sonuç” ve durma problemi geldi, ama zevkler kişiden kişiye değişebilir
    • Artış miktarı algılama Perl6’da eskiden beri vardı, yani yeni bir özellik değil
      Whatever hariç tutulursa, Perl6/Raku sonrasındaki yenilik daha çok tembel değerlendirme tarafında gibi görünüyor
    • Oldukça tutarlı
      (1,3,9...*)[4,5] sonucu (81 243) olur, (1,3,9...*)[(1..3)] sonucu ise (3 9 27) olur
      İç içe de kullanılabildiği için (1,2,4...*)[(1,2,4...*)[1,2,3]] gibi ifadeler de mümkün
  • Raku özellikleri arasından ilginç olanlar seçilip ele alınmış gibi
    Bana göre en önemli Raku özellikleri komut satırı arayüzü ve grammar
    Komut satırı arayüzü desteği yaygın bir özellik; örneğin docopt implementasyonları ve benimseme örnekleri var. Ancak Raku’da bu özellik yerleşik ve kullanımı rahat
    Buna karşılık grammar, bir programlama dilinin grameri birinci sınıf bileşen olarak sunması ve nesne yönelimli programlamayla gramer oluşturup birleştirmeye imkân vermesi bakımından nadir bir özellik

  • Bu projeyi birkaç yıldır takip ediyorum ve ilginç buluyorum; yine de Perl 6’nın bu aynanın içinden yolculukta fazlasıyla yolunu kaybetmiş gibi görünmesi gerçekten üzücü

    • Patrick Michaud’un bugünlerde nasıl olduğunu ve ne yaptığını merak ediyorum