【问题标题】:Executing a function randomly of a list of functions随机执行函数列表中的函数
【发布时间】: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


【解决方案1】:

你说,

如果输出为(),则再次调用该函数,否则返回输出。

这是一个奇怪的说法,因为没有“否则”——如果你的东西有时返回(),它永远不会返回除()之外的任何东西,因为没有其他相同类型的值!特别是,这意味着不可能到达您案例的_ 分支。

在您的语言中,如此处所示,语句基本上不计算数据。也许您应该更改Selection 构造函数以采用[(HVal, HStatement)] 而不是[HStatement](表示返回一些有趣的计算对,您可以在case 上连同语句一起在某个适当的分支中执行case),或者将语句计算的类型修改为比 () 更丰富的类型。

【讨论】:

  • 真的很抱歉!我可以看到我现在在描述问题时是如何犯错误的。我现在将修改我的帖子以包含函数定义。我认为我可能必须评估与语句绑定的守卫而不是整个 HStatement 本身,因为对HStatements 的所有评估都会产生()。然而,在代表选择时,这就是我在 Selection [HStatement] == Selection [If (HVal, HStatement)] 中已经这样做的方式
  • @JiangShi 是parseSelection 唯一调用parseIf 的解析器吗?如果是这样,我将加倍强调我的主张:Selection 不仅应该采用 [(HVal, HStatement)],而且语句的 If 构造函数也不应该存在。这是因为If 只允许在选择中使用,并且它是唯一允许在选择中使用的东西——因此将其拆分为单独的实体是没有意义的。 (如果parseIfparseSelection 以外的其他解析器调用,我会撤回“If 构造函数不应该存在”,但不会撤回对Selection 的建议更改。)
  • 是的,parseSelection 是唯一调用它的解析器!看看我开始拆分它们的原因是因为没有if 的子解析我无法正确解析选择,这就是为什么我的选择是由许多ifs 组成的。为什么这种增加的复杂性不好?
  • @JiangShi 1. 我不明白为什么拥有子解析器需要向HStatement 添加构造函数。例如,您调用了spaces 子解析器,但没有相应的构造函数。也许这是一个很好的新问题? 2. 增加的复杂性很糟糕,因为它引入了不必要的故障点:有缺陷的 Haskell 代码有可能构造包含非If 语句的选择(有缺陷的构造),编译器不可能看到仅匹配的考虑If 已完成(错误消耗)。
  • @JiangShi 这是修复Selection 的另一个好处,是的——我怀疑答案确实会变得非常明显。 ^_^
猜你喜欢
  • 2014-12-25
  • 1970-01-01
  • 2021-12-15
  • 1970-01-01
  • 1970-01-01
  • 2019-07-01
  • 2018-09-04
  • 2012-08-02
  • 1970-01-01
相关资源
最近更新 更多