Haskell'de yeni insanlar tarafından fark edilen en belirgin yenilik, dış dünya ile iletişim kurmakla ilgili saf olmayan dünya ile saf hesaplama ve algoritma dünyası arasında bir ayrım olması. Sıkça başlayan bir başlangıç sorusu, "Nasıl dönüşebilirim IO
, yani IO a
dönüşebilirim a
?" Bunun yolu, IO ve zincir efektleri gerçekleştiren kod yazmak için monad'ları (veya diğer soyutlamaları) kullanmaktır. Bu kod dış dünyadan veri toplar, bir model oluşturur, muhtemelen saf kod kullanarak bazı hesaplamalar yapar ve sonucu çıkarır.
Yukarıdaki model söz konusu olduğunda, IO
monaddaki GUI'leri manipüle etmede korkunç bir şey görmüyorum . Bu stille ortaya çıkan en büyük sorun, modüllerin artık oluşturulamamasıdır, yani, programımdaki ifadelerin küresel yürütme sırası hakkındaki bilgimin çoğunu kaybediyorum. Onu kurtarmak için, eşzamanlı, zorunlu GUI kodunda olduğu gibi benzer bir muhakeme uygulamak zorundayım. Bu arada, saf olmayan GUI kodu için, yürütme sırası IO
monad'ın >==
operatörünün tanımı nedeniyle açıktır (en azından sadece bir iş parçacığı olduğu sürece). Saf kod için, performansı artırmak veya sonuçta ortaya çıkan değerlendirmelerden kaçınmak için köşe durumlar hariç, hiç önemli değil ⊥
.
Konsol ve grafik IO arasındaki en büyük felsefi fark, ilkini uygulayan programların genellikle senkron tarzda yazılmasıdır. Bu mümkündür (sinyalleri ve diğer açık dosya tanımlayıcılarını bir kenara bırakarak) yalnızca bir olay kaynağı vardır: yaygın olarak adlandırılan bayt akışı stdin
. GUI'ler doğal olarak eşzamansızdır ve klavye olaylarına ve fare tıklamalarına tepki vermek zorundadır.
İşlevsel olmayan bir şekilde asenkron IO yapma felsefesine Fonksiyonel Reaktif Programlama (FRP) denir. ReactiveX gibi kütüphaneler ve Elm gibi çerçeveler sayesinde son zamanlarda saf olmayan, işlevsel olmayan dillerde çok fazla çekiş elde etti . Özetle, GUI öğelerini ve olay kaynakları olarak "gözlemlenebilir" adı verilen olay akışları gibi diğer şeyleri (dosyalar, saatler, alarmlar, klavye, fare gibi) görüntülemek gibidir. Bu olaylar gibi bilinen operatörleri ile birleştirilir map
, foldl
, zip
, filter
, concat
, join
, vb, yeni akışları elde edilir. Bu yararlıdır, çünkü programın kendisi scanl . map reactToEvents $ zipN <eventStreams>
, program N
tarafından şimdiye kadar dikkate alınan gözlemlenebilirlerin sayısına eşit olan programdan görülebilir .
FRP gözlemlenebilirleriyle çalışmak, bir akıştaki olaylar zamanında sıralandığı için birleştirilebilirliğin kurtarılmasını mümkün kılar. Bunun nedeni, olay akışı soyutlamasının tüm gözlemlenebilirleri kara kutular olarak görüntülemeyi mümkün kılmasıdır. Sonuç olarak, olay akışlarını işleçleri kullanarak birleştirmek, yürütme sırasında bazı yerel siparişleri geri verir. Bu beni, Haskell'deki tüm işlevlerin referans olarak şeffaf olması gerektiği gibi, programımın gerçekte hangi değişmezlere dayandığı konusunda çok daha dürüst olmaya zorlar: Programımın başka bir bölümünden veri çekmek istiyorsam, açık olmalıyım reklam, işlevlerim için uygun bir tür bildiriyor. (Saf olmayan kod yazmak için Etki Alanına Özgü bir dil olan IO monad, bunu etkili bir şekilde atlar)