My first ugly approach was:
allTerms :: Omega T
allTerms = do
which <- each [ 1,2,3 ]
if which == 1 then
return A
else if which == 2 then do
x <- allTerms
return $ B x
else do
x <- allTerms
y <- allTerms
return $ C x y
But then, after some cleaning up I reached this one liner
import Control.Applicative
import Control.Monad.Omega
import Control.Monad
allTerms :: Omega T
allTerms = join $ each [return A, B <$> allTerms, C <$> allTerms <*> allTerms]
Note that order matters: return A
has to be the first choice in the list above, or allTerms
will not terminate. Basically, the Omega
monad ensures a "fair scheduling" among choices, saving you from e.g. infiniteList ++ something
, but does not prevent infinite recursion.
An even more elegant solution was suggested by Crazy FIZRUK, exploiting the
Alternative
instance of Omega
.
import Control.Applicative
import Data.Foldable (asum)
import Control.Monad.Omega
allTerms :: Omega T
allTerms = asum [ pure A
, B <$> allTerms
, C <$> allTerms <*> allTerms
]
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…