我不够聪明,无法通过递归方案将 monad 线程化,所以我依赖于 recursion-schemes-ext,它具有 anaM 函数,用于运行带有 monadic 动作的变形。
我在这里做了一个(非常丑陋的)概念证明:
{-# LANGUAGE FlexibleContexts #-}
import Data.Functor.Foldable (ListF(..), Base, Corecursive)
import Data.Functor.Foldable.Exotic (anaM)
import System.Random
s :: String -> IO (Maybe Char)
s st = do
continue <- getStdRandom $ randomR (0, 2000 :: Int)
if continue /= 0
then do
getStdRandom (randomR (0, length st - 1)) >>= return . Just . (st !!)
else return Nothing
result :: (Corecursive t, Traversable (Base t), Monad m) => (String -> m (Base t String)) -> String -> m t
result f = anaM f
example :: String -> IO (Base String String)
example st = maybe Nil (\c -> Cons c $ c:st) <$> s st
final :: IO String
final = result example "asdf"
main = final >>= print
一些笔记
- 我嘲笑了你的
s
功能,因为我不熟悉monad-bayes
- 由于我们的最终列表位于 monad 中,因此我们必须严格构建它。这迫使我们制作一个有限列表(我允许我的
s
函数随机停止在大约 2000 个字符处)。
编辑:
下面是一个修改版本,确认结果函数可以生成其他递归结构(在本例中为二叉树)。注意 type offinal
和 value ofexample
是前面代码中仅有的两个发生变化的位。
{-# LANGUAGE FlexibleContexts, TypeFamilies #-}
import Data.Functor.Foldable (ListF(..), Base, Corecursive(..))
import Data.Functor.Foldable.Exotic (anaM)
import Data.Monoid
import System.Random
data Tree a = Branch a (Tree a) (Tree a) | Leaf
deriving (Show, Eq)
data TreeF a b = BranchF a b b | LeafF
type instance Base (Tree a) = TreeF a
instance Functor Tree where
fmap f (Branch a left right) = Branch (f a) (f <$> left) (f <$> right)
fmap f Leaf = Leaf
instance Functor (TreeF a) where
fmap f (BranchF a left right) = BranchF a (f left) (f right)
fmap f LeafF = LeafF
instance Corecursive (Tree a) where
embed LeafF = Leaf
embed (BranchF a left right) = Branch a left right
instance Foldable (TreeF a) where
foldMap f LeafF = mempty
foldMap f (BranchF a left right) = (f left) <> (f right)
instance Traversable (TreeF a) where
traverse f LeafF = pure LeafF
traverse f (BranchF a left right) = BranchF a <$> f left <*> f right
s :: String -> IO (Maybe Char)
s st = do
continue <- getStdRandom $ randomR (0, 1 :: Int)
if continue /= 0
then getStdRandom (randomR (0, length st - 1)) >>= return . Just . (st !!)
else return Nothing
result :: (Corecursive t, Traversable (Base t), Monad m) => (String -> m (Base t String)) -> String -> m t
result f = anaM f
example :: String -> IO (Base (Tree Char) String)
example st = maybe LeafF (\c -> BranchF c (c:st) (c:st)) <$> s st
final :: IO (Tree Char)
final = result example "asdf"
main = final >>= print