我正在编写一个程序,为人们分配比萨饼;除非库存耗尽,否则每个人都会得到一个披萨,最好是他们喜欢的披萨,在这种情况下,他们会递归地给出下一个喜欢的类型。
我的方法是计算一个人想要披萨的数量((User, Pizza), Int)
,对那些披萨进行排序,并通过使用状态monad来保存库存数量。
编写程序并进行类型检查:
allocatePizzasImpl :: [((User, Pizza), Int)]
-> State [(Pizza, Int)] [(User, Pizza)]
allocatePizzasImpl [] = return []
allocatePizzasImpl ((user, (flavor, _)):ranks) =
do inventory <- get
-- this line is never hit
put $ updateWith inventory (\i -> if i <= 0
then Nothing
else Just $ i - 1) flavor
next <- allocatePizzasImpl $ filter ((/= user) . fst) ranks
return $ (user, flavor) : next
我有一个帮助函数来提取结果:
allocatePizzas :: [Pizza]
-> [((User, Pizza), Int)]
-> [(User, Pizza)]
allocatePizzas pizzas rank = fst
. runState (allocatePizzasImpl rank)
$ buildQuotas pizzas
但是-- this line is never hit
指示的行是......从未受到任何GHCI断点的影响;此外,如果我打破回访,GHCI说inventory
不在范围内。
运行时,结果是为所有用户分配相同的披萨(有一个库存计数)。出了点问题,但我完全不知道如何继续。我是Haskell的新手,所以任何关于风格的评论都会受到赞赏=)
谢谢!
PS:为了完整性,updateWith
定义为:
updateWith :: (Eq a, Eq b)
=> [(a, b)] -- inventory
-> (b -> Maybe b) -- update function; Nothing removes it
-> a -- key to update
-> [(a, b)]
updateWith set update key =
case lookup key set of
Just b -> replace set
(unwrapPair (key, update b))
(fromMaybe 0 $ elemIndex (key, b) set)
Nothing -> set
where replace :: [a] -> Maybe a -> Int -> [a]
replace [] _ _ = []
replace (_:xs) (Just val) 0 = val:xs
replace (_:xs) Nothing 0 = xs
replace (x:xs) val i = x : (replace xs val $ i - 1)
unwrapPair :: Monad m => (a, m b) -> m (a, b)
unwrapPair (a, mb) = do b <- mb
return (a, b)
答案 0 :(得分:1)
我认为您的函数replace
已被破坏:
replace (_:xs) (Just val) 0 = val:xs
这并没有注意它所取代的价值。您不打算只替换与key
对应的货币对吗?
我想你想要
updateWith [] e k = []
updateWith ((k', v):kvs) e k
| k' == k = case e v of
Just v' -> (k, v'):kvs
Nothing -> kvs
| otherwise = (k', v) : updateWith kvs e k
答案 1 :(得分:0)
问题(忽略评论者提到的其他概念性事实)结果是使用fst
从状态中提取结果,由于某种原因不会导致实际计算国家。通过seq
运行结果修复了它。
我有兴趣知道为什么这就是这种情况!
编辑:正如丹尼尔瓦格纳在评论中指出的那样,我实际上并没有使用库存,结果证明这是真正的错误。将此标记为已接受。