【发布时间】:2021-03-12 17:45:17
【问题描述】:
=== HStatement 的评估(如果和选择栏)===
evalStatement_ :: Env -> HStatement -> IOThrowsError ()
evalStatement_ env (Do cond expr) = evalVal env cond >>= \x -> case x of
HBool False -> return ()
HBool True -> do
traverse_ (evalStatement_ env) expr
evalStatement_ env (Do cond expr)
evalStatement_ env (Skip skip) = return ()
evalStatement_ env (Print (HString val)) = getVar env val >>= \x -> liftIO $ putStrLn $ show x
evalStatement_ env (Print val) = evalVal env val >>= \x -> liftIO $ putStrLn $ show x
evalStatement_ env (Eval val) = do
result <- evalVal env val
return ()
=== 表示选择 & If ===
parseIf :: Parser HStatement
parseIf = do
string "("
cond <- parseArith
string ")->"
spaces
expr <- many1 $ parseStatements
spaces
return $ If (cond, expr)
parseSelection :: Parser HStatement
parseSelection = do
_ <- string "if"
spaces
selection <- many1 $ parseIf
spaces
_ <- string "fi"
spaces
return $ Selection selection
注意:如果选择的评估更改为以下,则程序运行并终止并给出输出:
evalStatement_ env (Selection if_ selection fi_ n) = evalStatement_ env (selection !! randIdx n) >>= \res -> if res == ()
then return ()
else return ()
然而,输出给出了介于 1 和 10 之间的不同数量的偶数。例如,一个输出将打印所有偶数,而另一个输出将打印数字 6。
tldr;有没有办法从函数列表中随机执行一个随机函数,如果结果不理想,重新执行该函数以执行一个随机函数,直到结果是idea?
我正在尝试编写一个执行函数列表中的随机条目的函数。列表中的每个条目都按以下方式构造:If (HVal, HStatement) -- If (Guard,Statement) where
HVal:
data HVal
= HInteger Integer
HBool Bool
HString String
HList [HVal]
Length HVal
Arith HVal Op HVal
Assign String HVal
deriving (Eq, Read)
HStatement:
data HStatement
= Eval HVal
| Print HVal
| Do HVal [HStatement]
| If (HVal, [HStatement])
| Selection [HStatement]
deriving (Eq, Read)
到目前为止,我尝试的是按照我的 question yesterday 使用 Asyncs race 函数。我的想法是,如果列表中存在 n 个条目的列表,这些条目构造为 If (HVal, HStatement),然后在仅包含其守卫被评估为 true 的 HStatements 列表的列表上运行 race 函数将返回执行最快的真正守卫的函数。
由于IO 的限制,尝试将这种raceAll 行为合并到我的代码库中对我来说太难了。我重新考虑了使用随机数生成器的方法。
所以现在我正在生成保护语句对列表的随机索引。我执行此列表中的条目并执行案例分析。如果输出是(),那么我再次调用该函数,否则我返回输出。为此,我使用了两个函数,其中selection 表示if's 的列表:
evalStatement_ env (If (cond, expr)) = evalVal env cond >>= \x -> case x of
HBool False -> return ()
HBool True -> traverse_ (evalStatement_ env) expr
evalStatement_ env (Selection selection) = evalStatement_ env (selection !! randIdx 1) >>= \res -> case res of -- randIdx produces an index between 0 and 1 representing the two branches in the selection block that could be taken
() -> evalStatement_ env (Selection selection)
_ -> return $ res
randIdx n = unsafePerformIO (getStdRandom (randomR (0, n - 1)))
以下面的程序为例:
f := [1 2 3 4 5 6 7 8 9 10]
n := 0
N := len(f)
Do (n < N)->
a := f.n
if ((a % 2) = 0)-> print(a)
((a % 1) = 1)-> print(a)
fi
n := n + 1
Od
这里发生的是程序根本没有输出并且没有终止。我期望发生的是在 0 和可能的分支数减一之间生成一个随机索引。然后这将被评估,如果它返回一个值,则会采用它,否则如果它是单元类型,则会生成一个新的随机索引并且会被使用。
如果选择的函数定义是traverse_ (evalStatement_ env) selection,我可以执行程序,但我只是不确定如何实现这种伪随机性。任何帮助将不胜感激!
【问题讨论】:
-
在我看来
randIdx 1总是会产生0,这使得程序的其余部分变得相当无趣。 -
@amalloy 即使产生的数字大于零也不起作用
-
如果将
randIdx更改为unsafePerformIO (getStdRandom (randomR (0, n ))),程序将终止并报错:Lang: Prelude.!!: index too large -
哎呀。 1.
randIdx的参数几乎可以肯定是一些涉及length selection的计算。 2. 不要为此使用unsafePerformIO。而是添加一个适合为评估堆栈生成随机性的一元效应。IO是一种选择;RandT StdGen将是另一个。 -
@DanielWagner 我只是使用
unsafePerformIO来快速启动该功能!一旦我得到我想要的工作,我就打算改变它
标签: haskell