ZuriHac: fonksiyonel programlama pratiği yapmak

Bu yılın haziran ayında İsviçre'nin küçük Rapperswil kasabasında bir etkinlik düzenlendi. ZuriHac. Bu sefer dilin yeni başlayanlarından kurucu babalarına kadar beş yüzden fazla Haskell sevdalısını bir araya getirdi. Organizatörler bu etkinliği hackathon olarak adlandırsa da klasik anlamda bir konferans ya da hackathon değil. Formatı geleneksel programcılardan farklıdır. Şans eseri ZuriHac'ı öğrendik, içinde yer aldık ve şimdi bu olağandışı buluşu anlatmayı görevimiz olarak görüyoruz!

ZuriHac: fonksiyonel programlama pratiği yapmak

Hakkımızda

Bu makale, St. Petersburg Ulusal Araştırma Üniversitesi İktisat Yüksek Okulu'nun “Uygulamalı Matematik ve Bilişim” programının 3. sınıf iki öğrencisi: Vasily Alferov ve Elizaveta Vasilenko tarafından hazırlanmıştır. İkimiz için de işlevsel programlama tutkusu, üniversitenin 2. yılında D. N. Moskvin'in verdiği bir dizi dersle başladı. Vasily şu anda proje ekibinin rehberliğinde Haskell'de cebirsel grafiklerin uygulandığı Google Summer of Code programına katılıyor Alg. Elizaveta, edindiği fonksiyonel programlama becerilerini, birleşme karşıtı algoritmanın uygulanmasına yönelik ders çalışmasında ve ardından tip teorisinde uyguladı.

Etkinlik formatı

Hedef kitle, açık kaynak projelerin sahipleri, bunların geliştirilmesine katılmak isteyen programcılar, işlevsel programlama araştırmacıları ve Haskell'e tutkuyla bağlı olan kişilerdir. Bu yıl, dünyanın dört bir yanından elliden fazla açık kaynak Haskell projesinden geliştiriciler, ürünleri hakkında konuşmak ve yeni insanların bu ürünlerin geliştirilmesine ilgi duymasını sağlamak için HSR Hochschule für Technik Rapperswil'de bir araya geldi.

ZuriHac: fonksiyonel programlama pratiği yapmak

Twitter'dan fotoğraf ZuriHac

Plan çok basit: Projeniz hakkında önceden birkaç teklif yazmanız ve bunları etkinlik sayfasında projeniz hakkında bilgi yayınlayacak olan organizatörlere göndermeniz gerekiyor. Ayrıca ilk gün proje yazarlarına ne yaptıklarını, ne yapılması gerektiğini çok kısa bir şekilde sahneden anlatmaları için otuz saniye süre veriliyor. Daha sonra ilgilenen kişiler yazarları arar ve görevler hakkında ayrıntılı olarak sorular sorar.

Henüz kendi açık projelerimiz yok ama mevcut projelere gerçekten katkıda bulunmak istediğimiz için düzenli katılımcı olarak kayıt yaptırdık. Üç gün boyunca iki grup geliştiriciyle çalıştık. Kodun ve canlı iletişimin ortak çalışmasının, proje yazarları ve katkıda bulunanlar arasındaki etkileşimi çok verimli hale getirdiği ortaya çıktı - ZuriHac'ta bizim için yeni olan alanları anlayabildik ve her birinde bir görevi tamamlayarak tamamen farklı iki takıma yardım edebildik. projelerden.

ZuriHac'ta değerli uygulamaların yanı sıra çeşitli dersler ve ustalık sınıfları da verildi. Özellikle iki dersi hatırlıyoruz. Bunlardan ilkinde, Newcastle Üniversitesi'nden Andrey Mokhov, uygulamalı işlevler ve monadlar arasında orta düzeyde olması gereken bir tür sınıfı olan seçici uygulamalı işlevler hakkında konuştu. Başka bir derste Haskell'in kurucularından Simon Peyton Jones, GHC derleyicisinde tür çıkarımının nasıl çalıştığından bahsetti.

ZuriHac: fonksiyonel programlama pratiği yapmak

Simon Peyton Jones'un konuşması. Twitter'dan fotoğraf ZuriHac

Hackathon sırasında gerçekleştirilen ustalık sınıfları, katılımcıların eğitim seviyelerine göre üç kategoriye ayrıldı. Projelerin geliştirilmesine katılan katılımcılara sunulan görevler de zorluk derecesine göre belirlendi. İşlevsel programcılardan oluşan küçük ama dost canlısı topluluk, yeni gelenleri memnuniyetle karşılıyor. Ancak Andrei Mokhov ve Simon Peyton Jones'un derslerini anlamak için üniversitede aldığımız fonksiyonel programlama dersi çok faydalı oldu.

Etkinliğe kayıt hem düzenli katılımcılar hem de proje yazarları için ücretsizdir. Katılım için başvurularımızı haziran ayı başında yaptık ve ardından bekleme listesinden onaylanmış katılımcılar listesine hızla aktarıldık.

Şimdi de geliştirilmesinde yer aldığımız projelerden bahsedeceğiz.

Pandoc

Pandoc aslında metin belgelerinin herhangi bir formattan herhangi bir formata evrensel bir dönüştürücüsüdür. Örneğin, docx'ten pdf'ye veya Markdown'dan MediaWiki'ye. Yazarı John MacFarlane, Berkeley'deki Kaliforniya Üniversitesi'nde felsefe profesörüdür. Genel olarak Pandoc oldukça ünlüdür ve bazı arkadaşlarımız Pandoc'un Haskell'de yazıldığını öğrendiğinde şaşırdılar.

ZuriHac: fonksiyonel programlama pratiği yapmak

Pandoc tarafından desteklenen belge formatlarının listesi. Sitede ayrıca bir grafiğin tamamı var ancak bu resim yazıya uymuyor.

Elbette Pandoc her format çifti için doğrudan dönüşüm sağlamaz. Bu kadar çeşitli dönüşümleri desteklemek için standart bir mimari çözüm kullanılır: önce belgenin tamamı özel bir dahili ara temsile çevrilir ve ardından bu dahili temsilden farklı formatta bir belge oluşturulur. Geliştiriciler dahili temsili Soyut Sözdizimi Ağacı anlamına gelen “AST” olarak adlandırıyor veya soyut sözdizimi ağacı. Ara gösterime çok basit bir şekilde bakabilirsiniz: tek yapmanız gereken çıktı formatını “yerel” olarak ayarlamaktır.

$ cat example.html
<h1>Hello, World!</h1>

$ pandoc -f html -t native example.html
[Header 1 ("hello-world",[],[]) [Str "Hello,",Space,Str "World!"]]

Haskell ile en azından biraz çalışmış olan okuyucular, bu küçük örnekten Pandoc'un Haskell'de yazıldığını zaten varsayabilirler: bu komutun çıktısı, Pandoc'un iç yapılarının, genellikle yapıldığı gibi oluşturulmuş bir dize temsilidir. Haskell'de, örneğin standart kütüphanede.

Yani burada, iç temsilin, her bir iç düğümde bir listesi bulunan özyinelemeli bir yapı olduğunu görebilirsiniz. Örneğin, en üst düzeyde bir öğenin listesi vardır - "merhaba dünya",[],[] niteliklerini içeren birinci düzey başlık. Bu başlığın içinde "Merhaba" dizisinin bir listesi ve ardından bir boşluk ve "Dünya!" dizisi gizlidir.

Gördüğünüz gibi dahili gösterim HTML'den pek farklı değil. Her bir iç düğümün, alt öğelerinin biçimlendirmesi hakkında bazı bilgiler sağladığı ve yaprakların belgenin gerçek içeriğini içerdiği bir ağaçtır.

Uygulama düzeyine inersek tüm belgenin veri türü şu şekilde tanımlanır:

data Pandoc = Pandoc Meta [Block]

Burada Blok tam olarak yukarıda belirtilen iç köşelerdir ve Meta, belge hakkında başlık, oluşturulma tarihi, yazarlar gibi meta bilgilerdir - bu farklı formatlar için farklıdır ve Pandoc mümkünse formattan formata çevirirken bu tür bilgileri korumaya çalışır. biçim.

Blok türündeki hemen hemen tüm kurucular (örneğin, Başlık veya Paragraf (paragraf)) argüman olarak nitelikleri ve alt düzey köşelerin listesini alır - kural olarak Satır İçi. Örneğin, Space veya Str Inline türünün yapıcılarıdır ve HTML etiketi de kendi özel Satır İçi'ne dönüşür. Bu türlerin tam bir tanımını vermenin bir anlamı olmadığını düşünüyoruz, ancak burada bulunabileceğini unutmayın. burada.

İlginçtir ki Pandoc türü bir monoiddir. Bu, bir tür boş belge olduğu ve belgelerin bir araya getirilebileceği anlamına gelir. Bu, Okuyuculara yazarken kullanışlıdır; rastgele bir mantık kullanarak bir belgeyi parçalara ayırabilir, her birini ayrı ayrı ayrıştırabilir ve ardından her şeyi tek bir belgede bir araya getirebilirsiniz. Bu durumda belgenin tüm bölümlerinden meta bilgiler aynı anda toplanacaktır.

Örneğin LaTeX'ten HTML'ye dönüştürürken, önce LaTeXReader adlı özel bir modül giriş belgesini AST'ye dönüştürür, ardından HTMLWriter adlı başka bir modül AST'yi HTML'ye dönüştürür. Bu mimari sayesinde ikinci dereceden sayıda dönüşüm yazmaya gerek yoktur; her yeni format için Reader ve Writer yazmanız yeterlidir ve olası tüm dönüşüm çiftleri otomatik olarak desteklenecektir.

Böyle bir mimarinin, yazılım mimarisi alanındaki uzmanlar tarafından uzun zamandır tahmin edilen dezavantajlarının da olduğu açıktır. Bunlardan en önemlisi sözdizimi ağacında değişiklik yapmanın maliyetidir. Değişiklik yeterince ciddiyse, tüm Okuyucular ve Yazıcılardaki kodu değiştirmeniz gerekecektir. Örneğin Pandoc geliştiricilerinin karşılaştığı zorluklardan biri karmaşık tablo formatlarını desteklemektir. Artık Pandoc yalnızca bir başlık, sütunlar ve her hücrede bir değer içeren çok basit tablolar oluşturabiliyor. Örneğin, HTML'deki colspan özelliği basitçe göz ardı edilecektir. Bu davranışın nedenlerinden biri, tabloları tüm formatlarda veya en azından birçok formatta temsil etmek için birleşik bir şemanın bulunmamasıdır - buna göre, dahili gösterimde tabloların hangi formda saklanması gerektiği belirsizdir. Ancak belirli bir görünümü seçtikten sonra bile tablolarla çalışmayı destekleyen tüm Okuyucuları ve Yazıcıları kesinlikle değiştirmeniz gerekecektir.

Haskell dilinin seçilmesinin nedeni yalnızca yazarların işlevsel programlamaya olan büyük sevgisidir. Haskell, kapsamlı metin işleme yetenekleriyle tanınır. Bir örnek kütüphanedir parsekten keyfi ayrıştırıcılar yazmak için işlevsel programlama kavramlarını (monoidler, monadlar, uygulamalı ve alternatif işlevler) aktif olarak kullanan bir kütüphanedir. Parsec'in tam gücü şurada görülebilir: örnek Basit bir zorunlu programlama dilinin tam bir ayrıştırıcısının ayrıştırıldığı HaskellWiki'den. Elbette Parsec Pandoc’ta da aktif olarak kullanılıyor.

Kısaca açıklanacak olursa, monadlar, önce bir şeyin, sonra diğerinin geldiği sıralı ayrıştırma için kullanılır. Örneğin, bu örnekte:

whileParser :: Parser Stmt
whileParser = whiteSpace >> statement

Öncelikle alanı ve ardından Ayrıştırıcı Stmt tipine sahip olan ifadeyi saymanız gerekir.

Ayrıştırma başarısız olursa geri almak için alternatif işlevler kullanılır. Örneğin,

statement :: Parser Stmt
statement = parens statement <|> sequenceOfStmt

Bu, ya parantez içindeki ifadeyi okumaya çalışmanız ya da birkaç ifadeyi sırayla okumaya çalışmanız gerektiği anlamına gelir.

Uygulamalı işlevler öncelikle monadlar için kısayol olarak kullanılır. Örneğin, tok fonksiyonunun bazı jetonları okumasına izin verin (bu, LaTeXReader'ın gerçek bir fonksiyonudur). Bu kombinasyona bakalım

const <$> tok <*> tok

Arka arkaya iki jeton okuyacak ve ilkini döndürecektir.

Tüm bu sınıflar için Haskell'in güzel sembolik operatörleri vardır, bu da Reader programlamanın ASCII sanatı gibi görünmesini sağlar. Bu harika koda hayran kalın.

Görevlerimiz LaTeXReader ile ilgiliydi. Vasily'nin görevi, LaTeX'te paket yazmak için yararlı olan mbox ve hbox komutlarını desteklemekti. Elizabeth, LaTeX belgelerinde epigraflar oluşturmanıza olanak tanıyan epigraf komutunu desteklemekten sorumluydu.

Hatrace

UNIX benzeri işletim sistemleri genellikle ptrace sistem çağrısını uygular. Program ortamlarında hata ayıklama ve simüle etmede kullanışlıdır ve programın yaptığı sistem çağrılarını izlemenize olanak tanır. Örneğin, çok kullanışlı strace yardımcı programı dahili olarak ptrace'i kullanır.

Hatrace, Haskell'de ptrace'e arayüz sağlayan bir kütüphanedir. Gerçek şu ki, ptrace'in kendisi çok karmaşıktır ve onu doğrudan kullanmak, özellikle de işlevsel dillerden oldukça zordur.

Hatrace başlangıçta strace gibi çalışır ve benzer argümanları kabul eder. Aynı zamanda ptrace'den daha basit bir arayüz sağlayan bir kütüphane olması bakımından strace'den farklıdır.

Hatrace'in yardımıyla, GHC Haskell derleyicisinde zaten hoş olmayan bir hata yakaladık - yanlış zamanda öldürülüyor, yanlış nesne dosyaları üretiyor ve yeniden başlatıldığında bunları yeniden derlemiyor. Sistem çağrılarıyla komut dosyası oluşturmak, hatayı tek seferde güvenilir bir şekilde yeniden üretmeyi mümkün kılarken, rastgele öldürmeler hatayı yaklaşık iki saat içinde yeniden oluşturdu.

Kütüphaneye sistem çağrısı arayüzleri ekledik - Elizaveta brk'yi ve Vasily mmap'i ekledi. Çalışmamızın sonuçlarına göre kütüphaneyi kullanırken bu sistem çağrılarının argümanlarını daha basit ve doğru bir şekilde kullanmak mümkündür.

Kaynak: habr.com

Yorum ekle