從this excellent blog post考慮以下簡稱代碼:這種循環遞歸如何提供期望的結果?
import System.Random (Random, randomRIO)
newtype Stream m a = Stream { runStream :: m (Maybe (NonEmptyStream m a)) }
type NonEmptyStream m a = (a, Stream m a)
empty :: (Monad m) => Stream m a
empty = Stream $ return Nothing
cons :: (Monad m) => a -> Stream m a -> Stream m a
cons a s = Stream $ return (Just (a, s))
fromList :: (Monad m) => [a] -> NonEmptyStream m a
fromList (x:xs) = (x, foldr cons empty xs)
不算太壞迄今爲止 - 一個單子,遞歸數據結構,並建立一個從列表中的一種方式。
現在考慮這個功能是從流選擇一個(均勻)隨機元素,採用恆內存:
select :: NonEmptyStream IO a -> IO a
select (a, s) = select' (return a) 1 s where
select' :: IO a -> Int -> Stream IO a -> IO a
select' a n s = do
next <- runStream s
case next of
Nothing -> a
Just (a', s') -> select' someA (n + 1) s' where
someA = do i <- randomRIO (0, n)
case i of 0 -> return a'
_ -> a
我沒有把握說的事情在最後四行無窮的神祕循環良好;結果a'
取決於someA
上的遞歸,其本身可能取決於a'
,但不一定。
我知道遞歸工作者在某種程度上積累了累積器中的潛在值,但我顯然無法對此進行充分的推理。
任何人都可以提供一個關於這個函數如何產生它的行爲的解釋嗎?
不應該最後兩個遞歸調用使用'xs''而不是'xs'? – is7s
@ is7s:當然,謝謝。 – hammar