In this section, we will explore two important type classes in Haskell: Functor and Foldable. These type classes provide powerful abstractions for working with data structures in a functional way.

Functor

What is a Functor?

A Functor is a type class that represents types that can be mapped over. In other words, a Functor is a container that you can apply a function to each element inside it.

Functor Type Class

The Functor type class is defined as follows:

class Functor f where
    fmap :: (a -> b) -> f a -> f b
  • fmap is a function that takes a function (a -> b) and a functor f a, and returns a new functor f b with the function applied to each element.

Example: Functor Instance for List

Lists are a common example of a Functor. Here’s how the Functor instance for lists is defined:

instance Functor [] where
    fmap = map

Using fmap

Here’s an example of using fmap with a list:

-- Define a function to double a number
double :: Int -> Int
double x = x * 2

-- Use fmap to apply the function to each element in the list
doubledList = fmap double [1, 2, 3, 4, 5]
-- Result: [2, 4, 6, 8, 10]

Practical Exercise: Functor

Exercise: Implement a Functor instance for a custom data type Maybe.

data Maybe a = Nothing | Just a

instance Functor Maybe where
    fmap _ Nothing  = Nothing
    fmap f (Just x) = Just (f x)

Solution:

-- Define a function to increment a number
increment :: Int -> Int
increment x = x + 1

-- Use fmap to apply the function to a Maybe value
incrementedMaybe = fmap increment (Just 5)
-- Result: Just 6

incrementedNothing = fmap increment Nothing
-- Result: Nothing

Foldable

What is Foldable?

Foldable is a type class that represents data structures that can be folded to a summary value. Folding is a way to reduce a data structure to a single value by iteratively applying a function.

Foldable Type Class

The Foldable type class is defined as follows:

class Foldable t where
    foldr :: (a -> b -> b) -> b -> t a -> b
  • foldr is a function that takes a binary function (a -> b -> b), an initial accumulator value b, and a foldable structure t a, and reduces it to a single value b.

Example: Foldable Instance for List

Lists are also a common example of a Foldable. Here’s how the Foldable instance for lists is defined:

instance Foldable [] where
    foldr = foldr

Using foldr

Here’s an example of using foldr with a list:

-- Define a function to sum two numbers
sum' :: Int -> Int -> Int
sum' x y = x + y

-- Use foldr to sum all elements in the list
sumList = foldr sum' 0 [1, 2, 3, 4, 5]
-- Result: 15

Practical Exercise: Foldable

Exercise: Implement a Foldable instance for a custom data type Tree.

data Tree a = Empty | Node a (Tree a) (Tree a)

instance Foldable Tree where
    foldr _ z Empty = z
    foldr f z (Node x left right) = foldr f (f x (foldr f z right)) left

Solution:

-- Define a function to multiply two numbers
multiply :: Int -> Int -> Int
multiply x y = x * y

-- Create a sample tree
sampleTree = Node 1 (Node 2 Empty Empty) (Node 3 Empty Empty)

-- Use foldr to multiply all elements in the tree
productTree = foldr multiply 1 sampleTree
-- Result: 6

Summary

In this section, we covered the Functor and Foldable type classes in Haskell. We learned how to use fmap to apply functions to elements inside functors and how to use foldr to reduce foldable structures to a single value. We also implemented custom instances for Maybe and Tree data types to reinforce these concepts.

Next, we will delve into more advanced functional programming concepts, such as Monads, in the following module.

© Copyright 2024. All rights reserved