假设我们在Haskell中有以下内容,
type Bag a = a -> Int
data Gems = Sapphire|Emerald|Diamond|Ruby deriving (Show)
myBag :: Bag Gems
myBag Sapphire = 3
myBag Diamond = 2
myBag Emerald = 0
emptyBag :: Bag Gems
emptyBag Sapphire = 0
emptyBag Diamond = 0
emptyBag Emerald = 0我们如何定义一个函数addItem,使得addItem x b将单次出现的项x添加到bag b中?
发布于 2013-01-05 12:47:15
你想要一个类型为
addItem :: Gems -> Bag Gems -> Bag Gems请注意,BagGems的定义与
addItem :: Gems -> (Gems -> Int) -> Gems -> Int因此,我们期待着addItem的定义开始
addItem gemToAdd bag gem = --some Int expression好的,让我们考虑一下其中的逻辑
gem是不同于gemToaAdd的宝石,我们应该得到bag提供给我们的相同
因此
addItem gemToAdd bag gem = if gem == gemToAdd then (bag gem) + 1 else bag gem你也可以写成
addItem gemToAdd bag gem | gem == gemToAdd = (bag gem) + 1
| otherwise = bag gem现在,这将产生一个错误,因为没有为Gems定义Eq。解决这个问题的最简单方法是定义
data Gems = Sapphire|Emerald|Diamond|Ruby deriving (Show, Eq)你就完事了
发布于 2013-01-06 07:11:09
首先,在Haskell中你不能改变任何东西,所有的东西都是不可变的。所以你现在想做的是错的。
myBag Sapphire = 3将始终为3。
所以你得退掉一个新包,而不是换一个。
此外,我认为创建一个Gem列表会比模式匹配更好。因此:
data Gems = Sapphire|Emerald|Diamond|Ruby deriving (Show, Eq)
type Gem = (Gems, Int)
type Bag = [Gem]您现在可以执行以下操作
[(Ruby, 30), (Sapphire, 20)] :: Bag例如。
接下来,我们希望能够调整这个袋子。
removeGem :: Gems -> Bag -> Bag
removeGem _ [] = []
removeGem gem (x:xs) | gem == (fst x) = removeGem gem xs
| otherwise = x : removeGem gem xs这段代码可以让你从包里取出宝石。这非常简单,它只是遍历列表并检查每一项是否为所选的宝石。如果不是这样,它会将其添加到函数列表中。最后,它将返回一个不包含所选gem的新列表。
使用此函数,我们可以使用以下代码将gem添加到包中:
addToBag :: Gem -> Bag -> Bag
addToBag item@(gem,amount) bag =
case lookup gem bag of
Nothing -> item : bag
_ -> let (Just oldAmount) = lookup gem bag
in (gem, (amount + oldAmount)) : (removeGem gem bag)这段代码可以让你添加新的gem到包中,如下所示:
(Diamond, 10) `addToBag` [(Ruby, 30), (Sapphire, 20)] :: Bag将返回:
[(Diamond,10),(Ruby,20),(Sapphire,30)]"lookup“是一个在元组列表中查找"key”的函数。键是第一个元组值,在我们的例子中是Gems。
如果查找没有找到我们想要添加的gem,它会简单地将其附加到列表中。
如果它找到它,我们会将它拥有的宝石数量存储到"oldAmount“中,删除宝石,并将新数量和旧数量添加在一起,为您的包创建一个新的宝石。例如:
(Ruby,20) `addToBag` [(Diamond,10),(Ruby,20),(Sapphire,30)]将返回:
[(Ruby,40),(Diamond,10),(Sapphire,30)]而不是:
[(Ruby,20),(Diamond,10),(Ruby,20),(Sapphire,30)]因此,它会累加数量,而不是一遍又一遍地添加相同的宝石名称。
如果你想从你的包中找到宝石和金额,你可以简单地使用"lookup“功能。
我希望这能回答你的问题。
https://stackoverflow.com/questions/14166641
复制相似问题