STDOUT ve safsızlığı


10

Fonksiyonel programlama hakkında birçok kitap ve makale okudum ve hala bazı çok temel kavramları kesin olarak anlayamamaktan utanıyorum.

Fonksiyonel programlamanın ana fikirlerinden biri, aynı girdinin daima aynı çıktıyı üretmesidir. Bu nedenle, diyelim ki, veritabanı sorgulama veya dosya yazma, tanım gereği tamamen işlevsel bir tarzda yapılamadı. Örneğin, monadlara ihtiyacımızın nedenlerinden biri budur.

Soru şu: STDOUT çıktısını neden saf olmayan bir şey olarak görüyoruz? Evet, herhangi bir dosya işleyici risklidir - verilerin her zaman yazılacağından asla emin olamayız. Peki ya STDOUT? Bunu neden güvenilir olmayan bir şey olarak düşünelim? Değerlendirmenin kendisi daha güvenilir değil mi? Yani, her zaman tetiği çekebiliriz ve böylece hesaplamayı kesebiliriz.

Yanıtlar:


6

Bu nedenle, diyelim ki, veritabanı sorgulama veya dosya yazma, tanım gereği tamamen işlevsel bir tarzda yapılamadı. Örneğin, monadlara ihtiyacımızın nedenlerinden biri budur.

Kimse monadlara "ihtiyaç duymaz", bu şeyleri tanımlamanın sadece bir yoludur. Aslında, muhtemelen en iyi yol bile değil. Bazı efekt yazım biçimleri , teklik türleri veya tam doğrusal mantığa dayalı bir sistem teoride daha ikna edici görünmektedir, ancak iyi bilinen tip sistemlerden daha radikal bir şekilde ayrılmaktadır ve ifade edilmesi daha karmaşıktır. Haskell'de bulunan Monadic IO, kullanılabilirlik ve basitlik arasında bir uzlaşmadır, çünkü esasen, dilde halihazırda kullanılan mevcut ML tarzı tip sistemle kolayca birlikte olacak şekilde tamamen zorunlu programlamayı modeller.

Soru şu: STDOUT çıktısını neden saf olmayan bir şey olarak görüyoruz? Evet, herhangi bir dosya işleyici risklidir - verilerin her zaman yazılacağından emin olamayız. Peki ya STDOUT? Bunu neden güvenilir olmayan bir şey olarak düşünelim? Değerlendirmenin kendisi daha güvenilir değil mi? Yani, her zaman tetiği çekebiliriz ve böylece hesaplamayı kesebiliriz.

Değil, biz de etmiyoruz. Bir bütün olarak programa giriş ve programdan çıktı, basitçe tüm programın tek bir büyük saf fonksiyon olarak ele alınmasından kaynaklanan argümanlar ve sonuçlar olarak görülebilir. Aynı şeyi stdin'den beslerseniz stdout'a yazdırdığı sürece, hala saf bir işlevdir. Aslında, Monadic IO'yu tanıtmadan önce Haskell, giriş ve çıkış için saf tembel akışlar kullanan bir akış tabanlı I / O sistemi kullandı. Düştü, çünkü görünüşe göre kullanmak için bir acıydı, bu da neden böyle bir şey duymadığınıza dair bir fikir verebilir. :]

Bu noktayı daha keskin bir şekilde ifade etmek için, minimalist ezoterik dili Lazy K'yi düşünün :

Lazy K, basit bir akış tabanlı I / O sistemine sahip, çöp toplanmış, referans olarak saydam bir fonksiyonel programlama dilidir.

Lazy K'yi bu tür dillerden ayıran şey, neredeyse diğer özellik eksikliğidir. Örneğin, entegre bir Hindley-Milner polimorfik tip sistemi sunmaz. Platformdan bağımsız GUI programlama ve diğer dillere bağlantı desteği olan kapsamlı bir standart kütüphane ile birlikte gönderilmez. Bu tür bir kütüphane de yazılamaz, çünkü diğer şeylerin yanı sıra, Lazy K yerleşik dışında herhangi bir işlevi tanımlamak veya bunlara atıfta bulunmak için herhangi bir yol sunmaz. Bu yetersizlik, sayılar, dizeler veya başka herhangi bir veri türü için eşleşen destek eksikliğiyle tamamlanmaktadır. Yine de, Lazy K Turing-complete.

(...)

Tembel K programları, matematiksel fonksiyonlarla aynı zamansız Platonik alemde yaşar, Unlambda sayfası "saf türetilmemiş lambda hesabının kutsanmış alemi" olarak adlandırır. Nasıl çöp toplama işlemi programcıdan bellek yönetimi sürecini gizliyorsa, referans şeffaflığı da değerlendirme sürecini gizler. Mandelbrot setinin bir resmini görüntülemek ya da bir Tembel K programını "çalıştırmak" için bazı hesaplamaların yapılması bir uygulama detayıdır. Fonksiyonel programlamanın özü budur.

(...)

Yan etkiler olmadan bir dilde girdi ve çıktı nasıl kullanılır? Belli bir anlamda, girdi ve çıktı yan etkiler değildir; tabiri caizse önden ve arkadan etkiler. Bu nedenle, bir programın olası girdilerin alanından olası çıkışların alanına kadar bir işlev olarak ele alındığı Lazy K'dadır.

Bundan daha işlevsel bir dil bulacağınızdan şüpheliyim!


Bununla birlikte, yukarıdakilerin yalnızca saf bir işlevin giriş ve çıkışını almak ve bunları bir şekilde "harici" olarak stdin / stdout'a bağlamak için geçerli olduğunu unutmayın. Bu ve gerçek sistem seviyesi I / O ilkellerine erişim arasında büyük bir fark var. Akarsulara okuma ve yazma uygulama ayrıntıları, dikkatle kapsüllenmedikçe safsızlığa sızabilir.

Bunun doğrudan Haskell'de yapamamanızın ana nedeni olduğunu düşünüyorum - mantıklı IO kullanımına kıyasla mantıklı kullanım durumları ince ve ikincisi için gerçek şeye erişmenin çok yararı var. Bu nedenle, örneğin, programa yönelik komut satırı argümanlarının main, sezgisel olarak olması gerektiği gibi görünse de , yalnızca argüman olarak iletilmediğine inanıyorum.

Sadece saf değerler olarak argümanları yakalamak ve daha sonra kullanmak - gerçi sen Belirli bir programda böyle bir şey en az bir sürümünü kurtarabilirsiniz işlevini programın geri kalanı için.interact


Efendim, itiraf etmeliyim, herhangi bir desteyle ilgili cevabınızı beğeniyorum. Kesinlikle bir kitap yazmalısın Haskell ve ben Şaka yapmıyorum.
shabunc

@shabunc: Bazen SO hakkındaki cevaplarımın toplamının zaten bir kitabın boyutu olmak için ne kadar yakın olduğunu merak ettim
CA McCann

Tam doğrusal mantığa dayalı bir sistem örneği verebilir misiniz? Varsa ilginç görünüyor.
yapılandırıcı

@configurator: Diğerleri için belirli dillere nasıl bağlandığımı fark ettim, ama doğrusal mantık için bir wikipedia sayfası? Ne yazık ki, bir örneğim olsaydı, verirdim. : [Tek duyduğum, CS araştırmasının kısmi prototipleri ve deney sistemleri. Eğer daha derine inmek istiyorsanız , doğrusal tip sistemlerde sizi başlatabilecek nispeten yaklaşılabilir bir malzeme .
CA McCann

3

İşlevsel bir programdaki saflık layık bir hedef olmakla birlikte, gerçek şu ki, bahsettiğiniz nedenlerden ötürü, önemsiz, faydalı her programın bazı kirlilikleri (veya "yan etkileri") olacaktır.

Tamamen saf programlar, tanım gereği, kapalı bir kara kutudur ve esasen ilgisizdir.

Fonksiyonel dil Haskell, bu sorunun çıktısı gibi yan etkileri izole ederek ilgilenir. monadlardaki . Monad, çıktı üretmeyi mümkün kılarken, tamamen işlevsel bir programlama tarzını korur.


Tabii, haklısın. Ama neden% 100 saflığın ütopya olduğunu anlıyorum. Soru STDOUT hakkında.
shabunc

1
STDOUT, tıpkı diğerleri gibi bir yan etkidir. Dahili olarak, monad gerekli olabilecek herhangi bir hata kontrolü gerçekleştirir.
Robert Harvey

evet, bu sorunun ne olduğudur - neden diğerleri gibi yan etki olarak kabul edilir?
shabunc

2
Dış dünyayı değiştiren her şey bir yan etki olarak kabul edilir.
Robert Harvey

1

Terminal cihazına bağlı değilseniz veya dosya tanımlayıcısını (herhangi bir nedenle) kapatırsanız STDOUT'a yazmak başarısız olabilir.

Ayrıca, STDOUT her zaman "konsol ekranı" değildir. Bazen başka bir programa aktarılır. Bazen boru kırılır.


0

"Dış dünyanın durumunu değiştirir" terimiyle saflığı düşünürseniz yardımcı olur. Bu bir konsola yazma, günlük dosyası, CD çıkarma veya "Füzeleri Başlatma" içerebilir.

Aynı zamanda yürütme açısından da bir sorun olabilir. Bir fonksiyonun herhangi bir yan etkisi olmadığını biliyorsanız, yarış koşulları veya benzeri olmayabileceğini kanıtlayabileceğiniz için eşzamanlılık için kolayca ayarlayabilirsiniz.


Dış dünyanın durumunu değiştirir veya dış dünyanın durumuna bağlıdır. Bu satırlarda daha fazla tartışma için bu soruya bakın .
MatrixFrog
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.