简体   繁体   English

函数的Haskell类型同义词

[英]Haskell Type Synonyms for Functions

Say we have the following in Haskell, 假设我们在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

How would we define a function addItem such that addItem xb adds a single occurrence of item x to bag b? 我们如何定义一个函数addItem,以便addItem xb将单个x项添加到bag b?

You want a function of the type 你想要一个类型的功能

addItem :: Gems -> Bag Gems -> Bag Gems

noting the definition of BagGems this is the same as 注意到BagGems的定义与此相同

addItem :: Gems -> (Gems -> Int) -> Gems -> Int

thus, we expect the definition of addItem to begin 因此,我们期望addItem的定义开始

addItem gemToAdd bag gem = --some Int expression

okay, so lets think about the logic also 好的,所以我们也要考虑逻辑

  1. If gem is a different Gem from gemToaAdd we should get out what ever bag gives us 如果gem是与gemToaAdd不同的宝石,我们应该拿出bag给我们的东西
  2. If it is the same than we should get one more 如果它是相同的,我们应该得到一个

thus 从而

addItem gemToAdd bag gem = if gem == gemToAdd then (bag gem) + 1 else bag gem

which you could also write 你也可以写

addItem gemToAdd bag gem | gem == gemToAdd = (bag gem) + 1
                         | otherwise       = bag gem

now, this will produce an error since Eq is not defined for Gems . 现在,这将产生一个错误,因为没有为Gems定义Eq The simplest way to fix that is to define 解决这个问题的最简单方法是定义

data Gems = Sapphire|Emerald|Diamond|Ruby deriving (Show, Eq)

and you are done 你完成了

First of all, you can't change anything in Haskell, everything is immutable. 首先,你不能在Haskell中改变任何东西,一切都是不可改变的。 So what you're trying to do right now is wrong. 所以你现在想做的事情是错的。

myBag Sapphire = 3

Will always be 3. 将永远是3。

So you will have to return a new bag instead of changing it. 所以你必须返回一个新的包而不是更换它。

Also, I think it would be better to create a list of Gems instead of pattern matching. 另外,我认为创建一个Gems列表而不是模式匹配会更好。 As such: 因此:

data Gems = Sapphire|Emerald|Diamond|Ruby deriving (Show, Eq)

type Gem = (Gems, Int)
type Bag = [Gem]

You can now do things such as 你现在可以做一些事情

[(Ruby, 30), (Sapphire, 20)] :: Bag

for example. 例如。

Next we want to be able to adjust this bag. 接下来我们希望能够调整这个包。

removeGem :: Gems -> Bag -> Bag
removeGem _ [] = []
removeGem gem (x:xs) | gem == (fst x)  = removeGem gem xs
                     | otherwise = x : removeGem gem xs

This code will let you remove a gem from a bag. 此代码将允许您从包中删除宝石。 It's very simple, it just goes through the list and checks each item if it's the selected gem. 它非常简单,它只是通过列表并检查每个项目是否是选定的宝石。 If that's not the case it will add it to the function list. 如果不是这样,它会将其添加到功能列表中。 In the end it will return a new list without the selected gem. 最后,它将返回一个没有选定gem的新列表。

With this function we can add gems to a bag with the following code: 使用此功能,我们可以使用以下代码将宝石添加到包中:

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)

This code will let you add new gems to a bag like so: 此代码可让您将新宝石添加到包中,如下所示:

(Diamond, 10) `addToBag` [(Ruby, 30), (Sapphire, 20)] :: Bag

Will return: 将返回:

[(Diamond,10),(Ruby,20),(Sapphire,30)]

"lookup" is a function that looks up a "key" in a list of tuples. “lookup”是一个在元组列表中查找“键”的函数。 The key being the first tuple value, in our case the Gems. 关键是第一个元组值,在我们的例子中是Gems。

If the lookup doesn't find the gem we want to add, it will simply append it to the list. 如果查找找不到我们想要添加的gem,它只会将它附加到列表中。

If however it does find it, we will store the amount it has of that gem into "oldAmount", delete the gem and add the new amount and old amount together to create a new gem for your bag. 但是如果确实找到了它,我们会将它拥有的宝石数量存储到“oldAmount”中,删除宝石并将新金额和旧金额一起添加,以便为您的包创建一个新的宝石。 For example: 例如:

(Ruby,20) `addToBag` [(Diamond,10),(Ruby,20),(Sapphire,30)]

Will return: 将返回:

[(Ruby,40),(Diamond,10),(Sapphire,30)]

instead of: 代替:

[(Ruby,20),(Diamond,10),(Ruby,20),(Sapphire,30)]

So it adds up the amount instead of adding the same gem name over and over. 因此,它会累计金额而不是一遍又一遍地添加相同的宝石名称。

If you want to find a gem and amount from your bag, you can simply use the "lookup" function. 如果你想从包中找到宝石和金额,你可以简单地使用“查找”功能。

I hope this answers your question. 我希望这回答了你的问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM