Haskell'deki monad sistemini anlamaya çalışıyorum. Önceki programlama deneyimimin yaklaşık% 80'i C'dedir, ancak ironik olarak Haskell'in zorunlu kısmı anlamak en zor olanıdır. Liste manipülasyonu ve tembel değerlendirme çok daha açıktı. Her neyse, ghc'yi bu kodu kabul etmek istiyorum. Kodun hiç mantıklı olmadığını biliyorum. En açıkçası, Bool
'u geçiyorum, burada IO Bool
bekleniyor. Ama bu tek sorun değil. Bunun aptalca bir soru olduğunu biliyorum, ama lütfen bana Haskell dilini daha iyi anlamama yardımcı olun. İştezorunlu döngü
import Control.Monad
while :: Monad m => m Bool -> m() -> m()
while cond action = do
c <- cond
when c $ do
action
while cond action
main :: IO()
main = do
i <- 0
while (i < 10) $ do
i <- i + 1
print i
Sonunda öyle yapmıştım. allocaArray
'un gerekli olmadığını biliyorum, ama kullanmak çok eğlenceliydi. Haskell'in gerçekten hiçbir sınırı yok, çok güçlü.
import Control.Monad
import Data.IORef
import Foreign.Ptr
import Foreign.Storable
import Foreign.Marshal.Array
while :: Monad m => m Bool -> m() -> m()
while cond action = do
c <- cond
if c then do
action
while cond action
else return()
main :: IO()
main = do
let n = 10
allocaArray n $ \p -> do
i <- newIORef 0
while (liftM (< n) (readIORef i)) $ do
i2 <- readIORef i
poke (advancePtr p i2) i2
modifyIORef i (+ 1)
writeIORef i 0
while (liftM (< n) (readIORef i)) $ do
i2 <- readIORef i
(peek $ advancePtr p i2) >>= print
modifyIORef i (+ 1)
Açık olanla başlayalım. Değişken bir değişken değil ve sadece bir monadınız olduğu için bir tane haline gelmiyor. 'i <- i + 1 'iki farklı' i 'anlamına gelir. –
Haskell'de "while" konstrüksiyonu oldukça nadiren kullanılır, bence tam olarak Haskell'de, "değişkenleri" doğal olarak, dilleri zorunlu kılan insanlar için kullanmanıza izin vermez. * Aynı şeyi daha garip bir şekilde yapabilirsin, ama 'Data.IORef' veya 'Control.Concurrent.MVar' gibi değişken referansları kullanmalısın. Gerçekten değişebilir bir güncellemeye ihtiyacınız olmadıkça, işlevsel olarak ifade etmek genellikle daha iyidir. –
Bu şekilde bir "IORef" kullanılmasının döngü sayacının "kutulu" olmasına yol açtığını unutmayın, böylece her bir yinelemede yeni bir "Int" kutusu tahsis edilir ve sayaca erişilmesi işaretçi indirmeyi içerir. Daha işlevsel bir sayıcıyla uğraştığınızda, GHC genellikle daha hızlı kodlara yol açarak kutuyu kaldırabilir. – dfeuer