series

  • Basic grammar for notes in the Haskell Guide to Fun Learning
  • Notes in the Haskell Guide to Fun Learning
  • Function of notes in the Haskell Guide to Fun Learning
  • Haskell’s Guide to Fun Learning notes of higher order functions
  • Module of notes in the Haskell Guide to Fun Learning
  • Custom types of notes in the Haskell Guide to Fun Learning
  • I/O notes from the Haskell Guide to Fun Learning

Custom data types

First, use the data keyword

dataType name = value constructor | constructor
data Bool = False | True
data Shape = Circle Float Float Float | Rectangle Float Float Float Float
Copy the code

A value constructor can be a value directly, such as True/False, or it can be a name followed by some type

The value constructor is essentially a function that returns a value of a data type, so Circle and Rectangle are not types, but functions:

ghci> :t Circle 
Circle: :Float -> Float -> Float -> Shape 
ghci> :t Rectangle 
Rectangle: :Float -> Float -> Float -> Float -> Shape
Copy the code

Then you can use this type

area: :Shape -> Float 
Note the pattern matching below
area (Circle _ _ r) = pi * r ^ 2 
area (Rectangle x1 y1 x2 y2) = (abs $ x2 - x1) * (abs $ y2 - y1)
Note the position of the Circle and Reactangle below
ghci> area $ Circle 10 20 10 
314.15927 
ghci> area $ Rectangle 0 0 100 100 
10000. 0
Copy the code

But now if you type Circle 1 1 5 in GHCI you get an error because Shape is not an instance of a Show class and cannot be called by Show. The solution is to add deriving (Show) after the sentence “data Shape”.

data Shape = Circle Float Float Float | Rectangle Float Float Float Float  
    deriving (Show)
Copy the code

To improve the

The Circle function takes three Float arguments, preceded by two coordinates of the center of the Circle and the last by the radius.

We use Point to optimize Shape to make it more readable:

data Point = Point Float Float deriving (Show) 
Note that the Point on the left is the type name and the Point on the right is the value constructor name.
data Shape = Circle Point Float | Rectangle Point Point deriving (Show)

area: :Shape -> Float 
area (Circle _ r) = pi * r ^ 2 
Note the pattern matching below
area (Rectangle (Point x1 y1) (Point x2 y2)) = (abs $ x2 - x1) * (abs $ y2 - y1)

ghci> area (Rectangle (Point 0 0) (Point 100 100)) 
10000. 0 
ghci> area (Circle (Point 0 0) 24) 
1809. 5574
Copy the code

export

module Shapes ( 
    Point(..) , - see here
    Shape(..) , - see here
    area.)where
Copy the code

Which Shape (..) Rectangle exports Shape and all of its value constructors. Shape(Circle, Rectangle). You can also omit the parentheses, so that no one else can use the Circle and Rectangle functions.

Use data + record syntax

data Person = Person {
    firstName: :String.age: :Int.height: :Float.phoneNumber: :String.flavor: :String
} deriving (Show)
Copy the code

This syntax automatically creates functions such as firstName, allowing values by field.

ghci> :t firstName 
firstName: :Person -> String
Copy the code

Type parameters (much like generics)

data Maybe a = Nothing | Just a
Copy the code

Maybe is a type constructor (not a type), a is a type argument, and a can be Int/Char /… , and Just is a function.

Since Haskell supports type derivation, we can Just write ‘a’ and Haskell knows that this is a Maybe Char type.

The list [] is a type constructor. [Int] exists, but there is no type [].

Examples of using the Maybe type:

ghci> Just "Haha"
Just "Haha" 
ghci> :t Just "Haha" 
Just "Haha": :Maybe [Char] 
ghci> :t Just 84 
Just 84: : (Num t) => Maybe t 
ghci> :t Nothing 
Nothing: :Maybe a 
ghci> Just 10: :Maybe Double 
Just 10. 0 
Copy the code

Data supports class constraints, but never use them

data (Ord k) = >Map k v = ...
Copy the code

The book says it’s just adding unnecessary code.

How do I make a Type instance of a type class

Simply add deriving (Eq) to the end of the data statement.

After an instance whose type is derived from Eq, the equality of their values can be determined directly using == or /=. Haskell first checks that the value constructors of the two values are consistent (there are only single-value constructors here) and then uses == to check that the data of each pair of fields is equal. The only requirement is that all fields must be of type Eq class.

Add deriving (Eq, Show, Read) to the list.

Enum type class

data Day = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday
-- or add typeclass
data Day = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday           
    deriving (Eq.Ord.Show.Read.Bounded.Enum) -- Integrating what I have learned so far
    
ghci> Wednesday
Wednesday 
ghci> show Wednesday
"Wednesday" 
ghci> read "Saturday": :Day 
Saturday
ghci> Saturday= =Sunday 
False 
ghci> Saturday= =Saturday 
True 
ghci> Saturday > Friday 
True 
ghci> Monday ` compare` Wednesday 
LT
ghci> minBound :: Day 
Monday 
ghci> maxBound :: Day 
Sunday
Copy the code

Type the alias

type String = [Char] -- Notice that not data is type
-- Supported parameters
type IntMap v = Map Int v
-- Equivalent to the following code in point-free style
type IntMap = Map Int
Copy the code

Either a b

data Either a b = Left a | Right b deriving (Eq.Ord.Read.Show)
Copy the code

Left “error message” and Right “data message”. How do I know that Right “data message” is constructed by Right?

Recursive data structures

data List a = Empty | Cons a (List a) 
    deriving (Show.Read.Eq.Ord)
    
ghci> Empty 
Empty 
ghci> 5 ` Cons` Empty 
Cons 5 Empty
ghci> 4 ` Cons` (5 ` Cons` Empty) 
Cons 4 (Cons 5 Empty) 
ghci> 3 ` Cons` (4 ` Cons` (5 ` Cons` Empty)) 
Cons 3 (Cons 4 (Cons 5 Empty))
Copy the code

Make a homemade list

infixr 5: - :data List a = Empty | a :-: (List a) deriving (Show.Read.Eq.Ord)

ghci> 3: - :4: - :5: - :Empty 
3: - :4: - :5: - :Empty)) 
ghci> let a = 3: - :4: - :5: - :Empty 
ghci> 100 :-: a 
100: - :3: - :4: - :5: - :Empty)))

infixr 5  (^ ^ + + + +) : :List a -> List a -> List a 
    Empty ^++ ys = ys 
    (x :-: xs) ^++ ys = x :-: (xs ^++ ys)

ghci> let a = 3: - :4: - :5: - :Empty 
ghci> let b = 6: - :7: - :Empty 
ghci> a ^++ b 
3: - :4: - :5: - :6: - :7: - :Empty))))
Copy the code

It’s the symbolism that HUANG xuan used when he said, “The functional is the thing.”

I’ve been updating my answer to the question “What is FP?” all year… I thought “close to/derived from mathematics or logic”. Isn’t imperative /OO language about mathematics and logic? Those who do not understand the difference in this explanation will probably not understand it… “Symbolism” is also a good description, given the history of THE FP language, and the two main ancestors of Lisp and ML (LCF) were both born of symbolist AI. Even though programming languages are symbolic, the more “FP” it is, the more it is possible to expect the behavior of a program to be detailed in symbols, rather than relying on all kinds of external functions, thus bringing about the terms “declarative,” “predictable,” and “deterministic.”

Make a binary search tree

data Tree a = EmptyTree | Node a (Tree a) (Tree a) deriving (Show)
The following function is used to create nodes
singleton :: a -> Tree a 
singleton x = Node x EmptyTree EmptyTree 
The following function is used to insert nodes
treeInsert: : (Ord a) => a -> Tree a -> Tree a 
treeInsert x EmptyTree = singleton x 
treeInsert x (Node a left right)       
    | x == a = Nodex left right &emsp; &emsp; &emsp; | x < a &emsp; =Nodea (treeInsert x left) right &emsp; &emsp; &emsp; | x > a &emsp; =Node a left (treeInsert x right)
The following function is used to determine whether an element is in the tree
treeElem: : (Ord a) => a -> Tree a -> Bool 
treeElem x EmptyTree = False 
treeElem x (Node a left right) &emsp; &emsp; &emsp;
    | x == a = True &emsp; &emsp; &emsp;
    | x < a = treeElem x left &emsp; &emsp; &emsp;
    | x > a = treeElem x right
    
- the use of

ghci> let nums = [8.6.4.1.7.3.5] 
ghci> let numsTree = foldr treeInsert EmptyTree nums 
ghci> numsTree 
Node 
    5
    (Node 3
        (Node 1 EmptyTree EmptyTree)
        (Node 4 EmptyTree EmptyTree(a))Node 7
        (Node 6 EmptyTree EmptyTree)
        (Node 8 EmptyTree EmptyTree))Copy the code