私はハスケルのモナドシステムを理解しようとしています。私のこれまでのプログラミング経験の約80%はC言語ですが、皮肉なことにハスケルの不可欠な部分は最も理解しにくい部分です。リスト操作と遅延評価ははるかに明確でした。とにかく私はghcにこのコードを受け入れさせたいと思っています。コードが意味をなさないことはわかっています。最も明白に、私はBool
を渡しています。IO Bool
が期待されます。しかしそれが唯一の問題ではありません。私はこれが愚かな質問だと知っていますが、ハスケル語の理解を深めてください。ハスケルの命令的ループ
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
ここで私は最終的にそれをやった方法です。私はallocaArray
が必要ではないことを知っていますが、使用するのはとても面白かったです。ハスケルは本当に限界がなく、非常に強力です。
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)
明らかにしましょう。 'i'は可変変数ではなく、モナドがあるので単純にはなりません。 'i < - i + 1 'は2つの異なる' i'を参照します。 –
ハスケルでは 'while'構造が使われることはほとんどありません。ハスケルでは、命令型言語に慣れている人にとって自然な方法で"変数 "を使用することは実際にはできません。あなたは同じことをもっと扱いにくいことができますが、 'Data.IORef'や' Control.Concurrent.MVar'のような可変参照を使わなければなりません。変更可能な更新が本当に必要な場合を除き、一般的に機能的に表現する方が良いです。 –
このように 'IORef'を使用すると、ループカウンタが「boxed」になるので、新しい「Int」ボックスが各繰り返しで割り当てられ、カウンタへのアクセスにはポインタ間接を伴います。より機能的なスタイルのカウンターを扱うとき、GHCは通常それをアンボックスすることができ、より高速なコードにつながります。 – dfeuer