I have a program that given a set of recipes and a desired output will tell me how many of the intermediate products I will need to make.
data Recipe = Recipe { name :: String
, ingredients :: [(Recipe, Int)]
} deriving (Eq)
instance Show Recipe where
show Recipe{name=n} = show n
foldRecipes :: (Integral a) => [(Recipe, a)] -> (Recipe, a) -> [(Recipe, a)]
foldRecipes acc r@(Recipe{ingredients=i}, n) =
acc ++ requirements [(recipe, fromIntegral count * n) | (recipe, count) <- i]
requirements :: (Integral a) => [(Recipe, a)] -> [(Recipe, a)]
requirements m =
foldl foldRecipes m m
main =
let dough = Recipe{ name = "dough", ingredients = [(flour, 200), (water, 200)] }
flour = Recipe{ name = "flour", ingredients = [] }
water = Recipe{ name = "water", ingredients = [] }
in putStrLn $ show $ requirements [(dough, 2)]
Outputs: [("dough",2),("flour",400),("water",400)
On my way to making this, I ran into the fact that the following version does not work, could somebody explain why? If I use an explicit Int
instead of Integral a
for the type signatures it does work.
foldRecipes :: (Integral a) => [(Recipe, a)] -> (Recipe, a) -> [(Recipe, a)]
foldRecipes acc r@(Recipe{ingredients=i}, _) =
acc ++ requirements i
Output:
test_unused.hs:10:30:
Could not deduce (a ~ Int)
from the context (Integral a)
bound by the type signature for
foldRecipes :: Integral a =>
[(Recipe, a)] -> (Recipe, a) -> [(Recipe, a)]
at test_unused.hs:8:16-76
`a' is a rigid type variable bound by
the type signature for
foldRecipes :: Integral a =>
[(Recipe, a)] -> (Recipe, a) -> [(Recipe, a)]
at test_unused.hs:8:16
Expected type: [(Recipe, a)]
Actual type: [(Recipe, Int)]
In the first argument of `requirements', namely `i'
In the second argument of `(++)', namely `requirements i'
In the expression: acc ++ requirements i