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.