Generics are a language feature that enable code reuse.
For example, it should not matter what type a list holds in order to compute its length.
That is why the length
function uses a generic type parameter a
in its type signature.
length : List a -> Int
When a type is generic over another type, we use a lowercase name for that other type, and call it a type parameter.
Common examples are the List
, Maybe
and Result
custom types.
-- Maybe is generic over the type a
type Maybe a
= Nothing
| Just a
someString : Maybe String
someString = Just "hello"
someInt : Maybe Int
someInt = Just 42
One important remark about names of type parameters, is that they can be multiple characters long. The only constraint is that they must be lowercase names. As such, when useful, we tend to give them descriptive names.
A type can be generic over multiple other types, and thus have multiple type parameters. In that case, every independent type gets a different lowercase name. Being independent does not prevent them from becoming the same type, it just enables them to be different.
-- Result is generic over the types error and value
type Result error value
= Ok value
| Err error
Record type aliases can also have type parameters, although it is less common.
-- Event is generic over the type a
type alias Event a =
{ at : Time
, data : a
}
Since types can be generic, so can functions.
Functions handling generic types can be writen, such as the Maybe.withDefault
.
withDefault : a -> Maybe a -> a
withDefault default maybe =
case maybe of
Just value -> value
Nothing -> default
Functions that take other functions as parameters are called higher order functions, and these can also be generic.
map : (a -> b) -> Maybe a -> Maybe b
map function maybe =
case maybe of
Just value ->
Just (function value)
Nothing ->
Nothing
In this exercise you're going to write a generic (/ magical!) TreasureChest, to store some treasure.
Define a TreasureChest
custom type with a single variant.
The variant should have an associated String
value, which will be used to store the password of the treasure chest.
The variant should also have an associate generic value, which will be used to store the treasure. This value is generic so that the treasure can be anything.
This function should take two parameters
String
(for trying a password)TreasureChest
generic custom typeThis function should check the provided password attempt against the String
in the TreasureChest
.
The function should return a Maybe
.
If the passwords match then return Just
with the generic value from the TreasureChest
(the treasure!)
If the passwords do not match then return Nothing
.
This (higher order) function should take two parameters
TreasureChest
generic custom type, also with the same generic typeThis function should call the multiplier function with the treasure in the chest.
The function should return a new TreasureChest, with the same password as the original, and with the multiplied treasure (the return)
Sign up to Exercism to learn and master Elm with 23 concepts, 94 exercises, and real human mentoring, all for free.