Я пишу программу для размещения пиццы для людей; каждый человек получит одну пиццу, в идеале своего любимого типа, если запасы не закончились, и в этом случае они будут рекурсивно возвращаться к их следующему любимому типу.Haskell: положить в Государственную монаду, кажется, отошел
Мой подход состоит в том, чтобы вычислить ((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, поэтому любые комментарии по стилю будут также оценены =)
Спасибо!
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] (http://stackoverflow.com/help/mcve). – bheklilr
Кроме того, 'allocatePizzasImpl' не выполняет typecheck (пытается сопоставить' (flavor, _) 'pattern с типом' Int'). –