我有一个程序给出了一组食谱,所需的输出将告诉我需要制作多少中间产品。
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)]
输出:[("dough",2),("flour",400),("water",400)
在我做这个的过程中,我遇到了以下版本不起作用的事实,有人可以解释原因吗?如果我使用明确的Int
代替Integral a
作为类型签名,那么它确实有效。
foldRecipes :: (Integral a) => [(Recipe, a)] -> (Recipe, a) -> [(Recipe, a)]
foldRecipes acc r@(Recipe{ingredients=i}, _) =
acc ++ requirements i
输出:
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
答案 0 :(得分:4)
foldRecipes :: (Integral a) => [(Recipe, a)] -> (Recipe, a) -> [(Recipe, a)]
foldRecipes acc r@(Recipe{ingredients=i}, _) =
acc ++ requirements i
上述方法不起作用,因为ingredients
始终包含类型[(Recipe, Int)]
的列表,而您的函数接受使用泛型整数类型Integral a
的列表。 a
和Int
是不同的类型,您无法使用++
连接不同类型的列表。
您的其他版本的功能有效,因为您使用fromIntegral
将Int
转换为更通用的类型。