-->

parameterized data structures in haskell [closed]

2019-10-04 03:51发布

问题:

Can you advise on how to represent parameterized data structures in haskell? e.g. in an application which represents contents of a garments shop, I might have instances of racks for men's and women's clothes. These parameters can be hierarchical, e.g. based on age groups. So I can have a rack(men(under14)), or a rack(women(adult)). Also, some constraints may apply to the rack parameters, e.g. no baby clothes. And as with java classes, I would need some member functions which would operate on these instances.

回答1:

How about something like this:

data Rack = Rack {allClothesOnRack :: [Clothing],
                  withClothing :: Clothing -> Maybe Rack,
                  withoutClothing :: Clothing -> Maybe Rack}

emptyRack :: (Clothing -> Bool) -> Rack
emptyRack isAcceptable = rack isAcceptable []

rack :: (Clothing -> Bool) -> [Clothing] -> Rack
rack isAcceptable = updated
  where updated items = Rack {allClothesOnRack = items,
                              withClothing = adding,
                              withoutClothing = removing}
        adding item | isAcceptable item = Just $ updated (item : items)
                    | otherwise         = Nothing
        removing item -- left as an exercise

You create a Rack with a function that specifies whether a particular item of clothing may be put on the rack. This function can use any property of Clothing (not defined in my example) it likes.

e.g. if isBabyClothing :: Clothing -> Bool returns True when given an item of baby clothing, then you create an empty baby clothes rack with emptyRack isBabyClothing.

Use the allClothesOnRack function to get a list of all the clothes on the rack.

e.g. allClothesOnRack (emptyRack isBabyClothing) will always yield [].

Use the withClothing and withoutClothing functions to add/remove an item of clothing to/from the rack. They each return Nothing if this is not possible (either the item of clothing may not be put on that rack, or it is not present on the rack and so cannot be removed), or Just the updated rack otherwise.



回答2:

as with Java classes, I would need some member functions which would operate on these instances

In Haskell, there is no such thing as "member" functions. All functions are simply functions.

Can you advise on how to represent parameterized data structures in haskell?

Sure. First of all, Rack sounds like it's just a list, so you could make a type synonym.

type Rack a = [a]

I'll just introduce you to a few features of Haskell that I think might be useful to you. This isn't the only way to do it, but I think it's a decent way to start. The first feature is called Algebraic data types (ADTs):

data Gender = Male | Female
            deriving (Eq, Show)

The type Gender has two possibilities, Male and Female. This particular example is basically Bool in disguise. Another ADT:

data Age = Baby | Child | PreTeen | Adult
         deriving (Eq, Show, Ord)

I'm no expert on clothing sizes, so tweak as necessary. Notice I've derived (Eq, Show, Ord). Eq gives us the ability to use == on values of that data type, Show lets us use show on values of that data type (similar to toString), and Ord lets us use comparison operators. With the definition I have provided, Baby < PreTeen will evaluate to True.

Now, then. Let's define clothing as another ADT. (-- begins a single-line comment)

data Clothing = Pants Gender Age
              | Shirt Gender Age
              | Skirt Age         -- assumed to be Female
              deriving (Show, Eq)

Here I've added fields to the options. You can create an article of clothing using one of the constructors. For example, Shirt Male Baby creates a value of type Clothing.

As you continue to learn Haskell, you may want to try using Generalized Algebraic Data Types (GADTs) and Typeclasses. You will probably need to use these features if you wish to create a Rack data type with functions on it that leverage the type of the rack to preserve predicates such as "this rack only has adult male clothing". However, I imagine these things are a bit over your head right now; instead try dave's approach with my data types, and run through some good introductory material to Haskell, such as Learn You a Haskell.