在 Haskell 中模拟全局列表以生成唯一的随机值

Immitating a global list in Haskell to generate a unique random value

提问人:makemepresident 提问时间:5/29/2022 更新时间:5/29/2022 访问量:119

问:

我目前正在构建一个玩具餐计划应用程序,并决定在 Haskell 中编写后端只是为了挑战自己。我遇到的问题在标题中进行了描述,我认为我需要一些全局的、可变的列表来记录以前的请求(它们不是同时发出的)。这是特别有问题的路线,特别是random_value的边界:

getMeal :: Pipe -> ScottyM ()
getMeal pipe = post "/get_meal/:mid?" $ do
    mid <- rescue (param "mid" :: ActionM Int) (\_ -> return 0)
    doc <- access pipe master "risto" $ do
        meal_count <- count $ select [] "meals"
        random_value <- getStdRandom (randomR (0, meal_count - 1))
        if mid == 0
            then findOne $ select ["id" =: random_value] "meals"
            else findOne $ select ["id" =: mid] "meals"
    case doc of
        Nothing -> text "Meal not found"
        Just a -> json $ Meal (at "id" a) (at "name" a) (at "calories" a) (at "yield" a) (at "ingredients" a)

但是,可以想象,如果此函数被调用 5 次,它可能会为这顿饭生成相同的值。在命令式语言中,我会初始化一个限制为 5 个项目的队列并完成它。探索使我相信状态单子可能是我应该寻找的地方,经过一些实验,我想出了:

type GetState = [Int]

pushLast :: Int -> State GetState ()
pushLast v = state $ \(x:xs) -> ((), if length xs == 5 then v:init xs else v:xs)

checkLastFive :: Int -> State GetState Bool
checkLastFive v = state $ \xs -> (elem v xs, xs)

我认为这可能过于复杂,所以我也想出了:

pushLastGet :: Int -> State [Int] ()
pushLastGet n = do
    s <- Control.Monad.State.get
    if elem n s
        then return ()
        else Control.Monad.State.put (n:s)

我遇到的主要问题是努力解决这个问题。我正在想象类似的东西(在类似 Haskell/Python 的伪代码中):

while True:
    random_value <- getStdRandom (randomR (0, meal_count - 1))
    if pushLastGet random_value != (): -- value was not in list
        break

此外,我正在努力完全掌握初始状态应该在哪里以及如何初始化,以及我的逻辑在 Haskell 中以及在包装它的单子的约束下究竟是什么样子的。

我还想过,也许有一种聪明的非一元方法可以做到这一点,但我的知识水平还没有完全达到。until

哈斯克尔 随机 全球 单子 可变

评论

0赞 n. m. could be an AI 5/29/2022
getStdRandom“命令性地”生成一个随机数,或者更确切地说,与任何其他函数的工作方式相同。您不担心拨打 5 次会返回 5 条相同的线路。或者你是?IOgetLine
0赞 makemepresident 5/29/2022
@n.1.8e9-where's-my-sharem。我知道随机数是命令式生成的(因为我的主要调用首先调用 initStdGen)。如果从客户端调用 getMeal 5 次,则可以得到以下生成的 ID [1,4,7,3,7],最初表示星期一到星期五;这意味着周三和周五都会随机选择同一顿饭(我不想要)。
1赞 n. m. could be an AI 5/29/2022
哦,你想生成不重复的随机数。您可能希望对有状态 Scotty 应用程序的基本示例感兴趣 github.com/scotty-web/scotty/blob/master/examples/...,但我认为这有点矫枉过正,您可能应该将此状态保留在 cookie 中,因为这是一个小的每用户状态。或者,保留包含此状态的用户数据的真实数据库(如果您不希望在用户从另一台计算机连接或重新启动服务器时丢失状态)。
1赞 Carl 5/29/2022
这不就是MVar的情况吗?
0赞 n. m. could be an AI 5/29/2022
@Carl,由于 Web 服务的并发性质,我链接的示例使用 Control.Concurrent.STM 中的 TVar 而不是 MVar。在更普通的应用程序中,MVar 似乎很好。

答: 暂无答案