【发布时间】:2015-04-15 18:16:39
【问题描述】:
我正在编写一个程序来分配比萨饼给人们;每个人都会得到一个披萨,最好是他们最喜欢的类型,除非库存用完,在这种情况下,他们会递归地获得下一个最喜欢的类型。
我的方法是计算((User, Pizza), Int) 来表示一个人想要说比萨的数量,对它们进行排序,然后通过使用状态单子进行递归以保持库存计数。
程序已编写并进行类型检查:
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 的新手,所以任何风格的 cmets 都会受到赞赏 =)
谢谢!
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)
【问题讨论】:
-
您能否包含
buildQuotas的定义?或者最好你可以将你的代码减少到MCVE。 -
另外,
allocatePizzasImpl不进行类型检查(尝试将(flavor, _)模式与Int类型匹配)。
标签: haskell state-monad