Os genéricos são uma funcionalidade da linguagem que permite reutilizar código.
Por exemplo, não deveria importar que tipo de valores uma lista contém para calcular o seu comprimento.
É por isso que a função length usa um parâmetro de tipo genérico a na sua assinatura de tipo.
length : List a -> Int
Quando um tipo é genérico em relação a outro tipo, usamos um nome em minúsculas para esse outro tipo e chamamos-lhe um parâmetro de tipo.
Exemplos comuns são os tipos personalizados List, Maybe e Result.
-- 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
Uma observação importante sobre os nomes dos parâmetros de tipo é que podem ter vários carateres. A única restrição é que têm de ser nomes em minúsculas. Por isso, quando é útil, tendemos a dar-lhes nomes descritivos.
Um tipo pode ser genérico em relação a vários outros tipos e, por isso, ter vários parâmetros de tipo. Nesse caso, cada tipo independente recebe um nome diferente em minúsculas. O facto de serem independentes não impede que se tornem o mesmo tipo, apenas permite que sejam diferentes.
-- Result is generic over the types error and value
type Result error value
= Ok value
| Err error
Os aliases de tipo de registo também podem ter parâmetros de tipo, embora seja menos comum.
-- Event is generic over the type a
type alias Event a =
{ at : Time
, data : a
}
Como os tipos podem ser genéricos, as funções também podem.
É possível escrever funções que lidam com tipos genéricos, como a Maybe.withDefault.
withDefault : a -> Maybe a -> a
withDefault default maybe =
case maybe of
Just value -> value
Nothing -> default
As funções que recebem outras funções como parâmetros chamam-se funções de ordem superior, e estas também podem ser genéricas.
map : (a -> b) -> Maybe a -> Maybe b
map function maybe =
case maybe of
Just value ->
Just (function value)
Nothing ->
Nothing
Neste exercício vais escrever um TreasureChest genérico (e mágico!) para guardar algum tesouro.
Define um tipo personalizado TreasureChest com uma única variante.
A variante deve ter um valor String associado, que será usado para guardar a palavra-passe do baú do tesouro.
A variante deve também ter um valor genérico associado, que será usado para guardar o tesouro. Este valor é genérico para que o tesouro possa ser qualquer coisa.
Esta função deve receber dois parâmetros
String (para tentar uma palavra-passe)TreasureChest
Esta função deve comparar a tentativa de palavra-passe fornecida com a String no TreasureChest.
A função deve devolver um Maybe.
Se as palavras-passe coincidirem, devolve Just com o valor genérico do TreasureChest (o tesouro!)
Se as palavras-passe não coincidirem, devolve Nothing.
Esta função (de ordem superior) deve receber dois parâmetros
TreasureChest, também com o mesmo tipo genéricoEsta função deve chamar a função multiplicadora com o tesouro que está no baú.
A função deve devolver um novo TreasureChest, com a mesma palavra-passe do original e com o tesouro multiplicado (o valor devolvido)
Inscreve-te no Exercism para aprenderes e dominares Elm com 28 conceitos110 exercícios, e mentoria humana real, tudo grátis.