提问人:makemepresident 提问时间:5/29/2022 更新时间:5/29/2022 访问量:119
在 Haskell 中模拟全局列表以生成唯一的随机值
Immitating a global list in Haskell to generate a unique random value
问:
我目前正在构建一个玩具餐计划应用程序,并决定在 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
答: 暂无答案
评论
getStdRandom
“命令性地”生成一个随机数,或者更确切地说,与任何其他函数的工作方式相同。您不担心拨打 5 次会返回 5 条相同的线路。或者你是?IO
getLine