class: center, middle
Clément Hurlin
https://github.com/smelc/tn-fp-haskell-course
- How to define generic types:
Maybe a,[a] - How to define concrete functions:
Maybe String -> String -> String
In this course:
Generic functionsGenericity in Haskell is twofold:
- Polymorphism: functions that work for generic types
- Classes constraints: require parameters to have some interface
???
-
Ask for functions that work for generic types:
- List functions:
filter,take, etc. - Map functions:
elem - Other containers:
fromMaybe,bimap
- List functions:
-
Ask for interfaces in
Java:equals,hashCode,cloneare interfaces; which are maybe supported, maybe notList,Map
class keyword is unrelated to object-oriented classes 💣
-- | Types whose values can be compared.
-- Expected to have the following properties:
-- Reflexivity: @x == x@ is @True@
-- Symmetry: @x == y@ is @y == x@
-- etc.
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
(/=) a b = not (a == b) -- Default implementation--
Define:
instance Eq Bool where
(==) a b = undefined--
instance Eq a => Eq (Maybe a) where
(==) _a _b = undefined
instance Eq a => Eq [a] where
(==) _xs _ys = undefined???
- Discuss
equalsandhashCodein Java
instance Eq a => Eq [a] where -- Build bigger instances from smaller ones
(==) [] [] = True
(==) (a : as) (b : bs) | a == b = as == bs
(==) _ _ | otherwise = Falsedata Ordering = LT | EQ | GT
-- | Totally ordered datatypes
class Ord a where
compare :: a -> a -> Ordering
(<=) :: a -> a -> Bool
-- Other operators: <, >, >=, min, max???
- Ask for the Java equivalent of
compare
--
-- | Types that can be pretty printed
class Show a where
show :: a -> String--
-- | Types whose values can be enumerated
class Enum a where
succ :: a -> a
pred :: a -> a
-- Other functions
class Bounded a where
minBound :: a
maxBound :: a???
- Ask for types that are instances of
EnumandBounded:IntandBool
deriving
data Version =
Alpha
| Beta
-- | Version number of the form "x.y.z"
| SemVer Int Int Int
deriving (Eq, Show)- Makes the compiler generate implementation for
Eq VersionandShow Version💪 - Java 15 (2020) has this for record classes
- Works for a number of classes:
Enum,Bounded,Functor,Writer, etc.
???
- Mention that IDEs do that
- Ask them what editors they use and why
Typeclasses bear similarities with Java interfaces, but:
- When a Java class is defined, all its interfaces must be declared.
- Typeclasses, however, don't have to be defined with the type.
class MonadIO m => MonadLogger m where
log :: String -> m ()
-- | Generic REST GET interface
class REST a b where
eval :: (MonadIO m, MonadLogger m) => a -> m b--
data PR = MkPR {
owner :: String,
repo :: String,
number :: Int
}
-- | Instance checking that a PR CI is green
instance REST PR Bool where
eval = undefinedIn addition, because of dynamic dispatch and subtyping, compare:
class Num a where
(+) :: a -> a -> aand
interface Addable<A> {
public A add(A right); // 'this' is the left operand
}Since there is no subtyping (and no concept of trait object or interface object), we can't build nor work on heterogeneous collections. Compare:
-- | Can sum a list of @a@s when @a@ has the 'Num' capability.
-- But all the items in the list must have the concrete type @a@,
-- and the returned value will have the same type @a@.
sumList :: Num a => [a] -> ainterface Num { ... }
class NInt implements Num { ... }
class NDouble implements Num { ... }
/** 'nums' can contain some items of concrete type NInt,
* and some items of concrete type NDouble at the same time.
* The returned value can be either a NInt or NDouble. */
Num sumList(nums: List<Num>) { }-- | A semigroup is a type whose values can be reduced or aggregated
-- Instances should satisfy @x <> (y <> z) = (x <> y) <> z@
class Semigroup a where
(<>) :: a -> a -> adata BankAction =
-- | Une dépense
Spend Int
-- | Un gain
| Earn Int
-- | Compte cloturé
| Close--
instance Semigroup BankAction where
Spend i <> Spend j = Spend (i + j)
Spend i <> Earn j = Spend (i - j)
Close <> _ = Close
_ <> Close = Close
Earn i <> Spend j = Earn (i - j)
Earn i <> Earn j = Earn (i + j)???
- Ask the version with
Natin place ofInt
--
instance Semigroup [a]instance Semigroup a => Semigroup (Maybe a)
class Semigroup a => Monoid a where
-- | The neutral element
mempty :: a
-- | Merging operation
mappend :: a -> a -> a
-- | Reduction, has a default implementation
mconcat :: [a] -> a???
- Show the laws on
Hoogle - Ask for
memptyandmappendon lists
--
-- Only >= 0 number of votes makes sense
type Nat = Word16
data Reactions = MkReactions {
hearts :: Nat,
thumbsUp :: Nat,
thumbsDown :: Nat
}???
- Ask to write
mempty - Ask to write
mappend - Implement
instance Monoid (a, b)
instance (Monoid a, Monoid b) => Monoid (a,b) where
mempty = (mempty, mempty)
(a,b) `mappend` (c,d) = (a `mappend` c, b `mappend` d)- Ask for another monoid implementation (hits in search of multiple files)
class Functor f where
-- | Apply a function to an element wrapped in something ('f')
fmap :: (a -> b) -> f a -> f b> import Data.List.Extra
> :type upper
upper :: String -> String
> applyUpper = fmap upper
> :type applyUpper
applyUpper :: Functor f => f String -> f String--
> applyUpper (Just "foo")
> applyUpper (Right "foo" :: Either Int String)--
- Instances we've seen before:
Maybe a[a]
From course 2:
data Interval a = MkInterval {
start :: a,
end :: a
}
deriving Functor- Write
Functor Interval
QuickCheck is a library for testing properties of functions.
-- | Random generation and shrinking of values.
class Arbitrary a where
-- | A generator of 'a'
arbitrary :: Gen a
-- | Given an 'a', smaller versions of 'a'
shrink :: a -> [a]
-- | Generates one of the given values
elements :: [a] -> Gen a
-- | Chooses one of the given generators, with a weighted random distribution.
frequency :: [(Int, Gen a)] -> Gen a???
- Show
class Testableon Hoogle
-- | @makeURL "http" "google.fr" "search/advanced"@ returns
-- @"http://www.google.fr/search/advanced"@
makeURL :: String -> String -> String -> String
makeURL = undefined--
newtype Protocol = MkProtocol String
newtype Hostname = MkHostname String
newtype Segments = MkSegments [String]
makeURL' :: Protocol -> Hostname -> Segments -> String
makeURL' = undefinednewtype:
- Cost-free (runtime) disambiguation 💪
⚠️ It's just names!⚠️
data User = MkUser { name :: String, avatar :: FilePath, id :: Int }
-- | @authenticate user password@ tries to authenticate @user@ with @password@
authenticate :: User -> String -> Bool
authenticate = undefined--
data Guest
data Authenticated
-- @type@ defines aliases (shortcuts)
type UserWithAuthStatus a = User
authenticate' :: User
-> String
-> Either String (UserWithAuthStatus Authenticated)
authenticate' = undefined--
Phantom types:
- Use type parameters as markers to distinguish data
- Could you do that in Java?
Typeclasses:
- Choose runtime behavior based on static types (/= dynamic dispatching)
- Leverage the compiler's generation capabilities
- Build APIs and features bottom up:
- from small values, to more structured values.
- https://learnyouahaskell.github.io/types-and-typeclasses.html#typeclasses-101
- http://book.realworldhaskell.org/read/using-typeclasses.html
- https://wiki.haskell.org/Typeclassopedia

