Haskell types and typeclasses

Source: Internet
Author: User
Algebraic Data Types

In the previous chapter, we talked about some built-in Haskell types and typeclass. In this chapter, we will learn the construction types and typeclass methods.

We have seen many types, suchBool,Int,Char,MaybeWait, but in Haskell, how should we construct our own types? Good question. One way is to useDataKeyword. Let's take a look.BoolDefinition in the Standard Library:

data Bool = False | True

DataTo define a new type.=The left endBool,=IsValue Constructor(Value Constructor), They specify the possible values of this type.|Read this statement as "or ".:BoolThe type value can beTrueOrFalse. The first letter of the type name and value constructor must be capitalized.

Similar, we can imagineIntType Declaration:

data Int = -2147483648 | -2147483647 | ... | -1 | 0 | 1 | 2 | ... | 2147483647

Both the header and end values are represented by the constructor.IntThe minimum and maximum values of the type. Note that the true type declaration is not long. This is only for ease of understanding. We use ellipsis to represent a large number omitted in the middle.

Let's look at the graphical representation in Haskell. Indicates that a circle can use a tuple, such(43.1,55.0,10.4), The first two items indicate the center position, and the last point indicates the radius. It sounds good, but 3d vectors or anything else may be in this form! A better way is to construct a chart type by yourself. Assume that the image can be a circle or a rectangle ):

data Shape = Circle Float Float Float | Rectangle Float Float Float Float

What is this?CircleThe value constructor of has three items, all of which are float. We can see that when defining the value structure, we can follow several types to indicate the types of values it contains. Here, the first two items represent the coordinates of the center, and the last item represents the radius.RectangleThe value constructor of takes fourFloatItem. The first two items represent the coordinates in the upper left corner, and the last two items represent the coordinates in the lower right corner.

When talking about "field", it should actually be "Parameters ). A value constructor is essentially a function that returns a value of the type. Let's take a look at the two values to construct the sub-type declaration:

ghci> :t Circle 
Circle :: Float -> Float -> Float -> Shape 
ghci> :t Rectangle 
Rectangle :: Float -> Float -> Float -> Float -> Shape

Cool. In this case, the value constructor is no different from a common function. Who wants it? Let's write a function to calculate the graphic area:

surface :: Shape -> Float 
surface (Circle _ _ r) = pi * r ^ 2 
surface (Rectangle x1 y1 x2 y2) = (abs $ x2 - x1) * (abs $ y2 - y1)

It is worth mentioning that its type declaration indicates that the function obtainsShapeAnd returnsFloatValue. WriteCircle -> FloatNo, becauseCircleNot a type. The actual type should beShape. This cannot be written.True->FalseThe truth is the same. Then, the pattern matching we use is for the value constructor. We have previously matched[],FalseOr5They are all constructors that do not contain parameter values.

We only care about the radius of the circle, so we do not need to care about the first two items of the coordinate:

ghci> surface $ Circle 10 20 10 
314.15927 
ghci> surface $ Rectangle 0 0 100 100 
10000.0

Yay, it works! However, if we try to outputCircle 10 20Go to the console and you will get an error. This is because Haskell does not know the string representation method of this type. Think about it. When we output a value to the console, Haskell will first callshowThe function outputs the string representation of this value. Therefore, let usShapeType becomes a member of the show type class. You can modify it as follows:

data Shape = Circle Float Float Float | Rectangle Float Float Float Float deriving (Show)

Do not go into details firstDeriving(Derived), you can first understand:dataAddderiving (Show)Then Haskell will automaticallyShowType class. GoodBecause the value constructor is a function, we can give itmap, Using it for all calls, and everything that common functions can do.

ghci> Circle 10 20 5 
Circle 10.0 20.0 5.0 
ghci> Rectangle 50 230 60 90 
Rectangle 50.0 230.0 60.0 90.0

If we want to take a group of concentric circles with different radius, we can do this:

ghci> map (Circle 10 20) [4,5,6,6] 
[Circle 10.0 20.0 4.0,Circle 10.0 20.0 5.0,Circle 10.0 20.0 6.0,Circle 10.0 20.0 6.0]

Our types can also be better. Add a type that represents the midpoint of a two-dimensional space.ShapeEasier to understand:

data Point = Point Float Float deriving (Show) 
data Shape = Circle Point Float | Rectangle Point Point deriving (Show)

Note:PointIts type and value constructor use the same name. There is no special meaning. In fact, this type of name duplication is very common when a type contains unique value constructor. Okay, now ourCircleContains two items, one isPointType, one isFloatType.RectangleSimilarly, we have to modifysurfaceFunction to adapt to changes in the type definition.

surface :: Shape -> Float 
surface (Circle _ r) = pi * r ^ 2 
surface (Rectangle (Point x1 y1) (Point x2 y2)) = (abs $ x2 - x1) * (abs $ y2 - y1)

The only thing that needs to be modified is the mode. InCircleWe ignore the entirePoint. InRectangleWe use a nested mode to obtainPoint. For some reasonPoint.

ghci> surface (Rectangle (Point 0 0) (Point 100 100)) 
10000.0 
ghci> surface (Circle (Point 0 0) 24) 
1809.5574

How do I write a function that indicates moving a graph? It should takeShapeAnd represent the two numbers of displacement, return a new position in the image.

nudge :: Shape -> Float -> Float -> Shape 
nudge (Circle (Point x y) r) a b = Circle (Point (x+a) (y+b)) r 
nudge (Rectangle (Point x1 y1) (Point x2 y2)) a b = Rectangle (Point (x1+a) (y1+b)) (Point (x2+a) (y2+b))

Concise and clear. Let's give this one more.ShapePoint plus the amount of displacement.

ghci> nudge (Circle (Point 34 34) 10) 5 10 
Circle (Point 39.0 44.0) 10.0

If you do not want to directly processPointWe can create an auxiliary function (auliliary function), first create a graph from the origin, and then move them.

baseCircle :: Float -> Shape 
baseCircle r = Circle (Point 0 0) r 
 
baseRect :: Float -> Float -> Shape 
baseRect width height = Rectangle (Point 0 0) (Point width height)
ghci> nudge (baseRect 40 100) 60 23 
Rectangle (Point 60.0 23.0) (Point 100.0 123.0)

Without a doubt, you can export your data type to the module. You just need to write your type together with the function to be exported. In the brackets that follow, list the constructors of the values to be exported and separate them with commas. If you want to export all the values to construct the child, write...

To export all functions and types defined here to a module, you can do this:

module Shapes 
( Point(..) 
, Shape(..) 
, surface 
, nudge 
, baseCircle 
, baseRect 
) where

OneShape(...), And we export it.ShapeAll values of constructor. This allows anyone to import our modules.RectangleAndCircleValue ConstructorShape. This is related to writingShape(Rectangle,Circle)Equivalent.

We can choose not to export anyShapeTo construct the sub-function, so that the user using our module can only use the auxiliary function.baseCircleAndbaseRectTo obtainShape.Data.MapThis is the set, noMap.Map [(1,2),(3,4)]Because it does not export any value to the constructor. But you can useMap.fromListThis auxiliary function is used to obtainmap. It should be remembered that the value constructor is just a function. If you do not export them, you will be denied from using our module to call them. However, you can use other functions that return this type to obtain this type of value.

The value constructor without exporting data types hides their internal implementations, so that the type abstraction is higher. At the same time, the user of our module cannot use this value to construct sub-pattern matching.

 

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.