Na verdade, é apenas um construtor de dados normal que é definido no Prelude , que é a biblioteca padrão que é importada automaticamente para cada módulo.
O que talvez seja, estruturalmente
A definição é mais ou menos assim:
data Maybe a = Just a
| Nothing
Essa declaração define um tipo,, Maybe aque é parametrizado por uma variável de tipo a, o que significa apenas que você pode usá-lo com qualquer tipo no lugar de a.
Construindo e Destruindo
O tipo possui dois construtores, Just ae Nothing. Quando um tipo tem vários construtores, significa que um valor do tipo deve ter sido construído com apenas um dos construtores possíveis. Para este tipo, um valor foi construído por meio de Justou Nothing, não há outras possibilidades (sem erro).
Como Nothingnão tem tipo de parâmetro, quando é usado como construtor, ele nomeia um valor constante que é membro do tipo Maybe apara todos os tipos a. Mas o Justconstrutor tem um parâmetro de tipo, o que significa que quando usado como um construtor ele atua como uma função de tipo apara Maybe a, ou seja, tem o tipoa -> Maybe a
Portanto, os construtores de um tipo constroem um valor desse tipo; o outro lado das coisas é quando você gostaria de usar esse valor, e é aí que a correspondência de padrões entra em jogo. Ao contrário das funções, os construtores podem ser usados em expressões de vinculação de padrão e esta é a maneira pela qual você pode fazer a análise de caso de valores que pertencem a tipos com mais de um construtor.
Para usar um Maybe avalor em uma correspondência de padrão, você precisa fornecer um padrão para cada construtor, assim:
case maybeVal of
Nothing -> "There is nothing!"
Just val -> "There is a value, and it is " ++ (show val)
Nesse caso, expressão, o primeiro padrão corresponderia se o valor fosse Nothing, e o segundo corresponderia se o valor fosse construído com Just. Se o segundo corresponder, ele também vincula o nome valao parâmetro que foi passado ao Justconstrutor quando o valor com o qual você está correspondendo foi construído.
O que talvez signifique
Talvez você já saiba como isso funciona; não há realmente nenhuma mágica para os Maybevalores, é apenas um tipo de dados algébrico Haskell (ADT) normal. Mas é bastante usado porque efetivamente "levanta" ou estende um tipo, como Integerno seu exemplo, para um novo contexto no qual ele tem um valor extra ( Nothing) que representa uma falta de valor! O sistema de tipo então requer que você verifique esse valor extra antes de permitir que você obtenha o Integerque pode estar lá. Isso evita um número notável de bugs.
Muitas linguagens hoje lidam com esse tipo de valor "sem valor" por meio de referências NULL. Tony Hoare, um eminente cientista da computação (ele inventou o Quicksort e é um vencedor do Prêmio Turing), reconhece isso como seu "erro de um bilhão de dólares" . O tipo Maybe não é a única maneira de consertar isso, mas provou ser uma maneira eficaz de fazer isso.
Talvez como um Functor
A ideia de transformar um tipo em outro de modo que as operações no tipo antigo também possam ser transformadas para funcionar no novo tipo é o conceito por trás da classe de tipo Haskell chamada Functor, que Maybe atem uma instância útil de.
Functorfornece um método chamado fmap, que mapeia funções que variam de valores do tipo base (como Integer) para funções que variam de valores do tipo levantado (como Maybe Integer). Uma função transformada com fmappara trabalhar em um Maybevalor funciona assim:
case maybeVal of
Nothing -> Nothing -- there is nothing, so just return Nothing
Just val -> Just (f val) -- there is a value, so apply the function to it
Portanto, se você tem um Maybe Integervalor m_xe uma Int -> Intfunção f, pode fmap f m_xaplicar a função fdiretamente ao Maybe Integersem se preocupar se ela realmente tem um valor ou não. Na verdade, você poderia aplicar uma cadeia inteira de Integer -> Integerfunções elevadas aos Maybe Integervalores e apenas se preocupar em verificar explicitamente uma Nothingvez quando terminar.
Talvez como uma mônada
Não tenho certeza de como você está familiarizado com o conceito de a Monadainda, mas pelo menos você já usou IO aantes, e a assinatura de tipo IO aé notavelmente semelhante a Maybe a. Embora IOseja especial por não expor seus construtores para você e, portanto, só pode ser "executado" pelo sistema de tempo de execução Haskell, ainda é um Functoralém de ser um Monad. Na verdade, há um sentido importante em que a Monadé apenas um tipo especial de Functorcom alguns recursos extras, mas este não é o lugar para entrar nisso.
De qualquer forma, as Mônadas gostam de IOtipos de mapas para novos tipos que representam "cálculos que resultam em valores" e você pode transformar funções em Monadtipos por meio de uma fmapfunção muito parecida com a chamada liftMque transforma uma função regular em um "cálculo que resulta no valor obtido pela avaliação do função."
Você provavelmente adivinhou (se já leu até aqui) que Maybetambém é a Monad. Ele representa "cálculos que podem não retornar um valor". Assim como no fmapexemplo, isso permite que você faça vários cálculos sem ter que verificar explicitamente os erros após cada etapa. E, de fato, da maneira como a Monadinstância é construída, um cálculo de Maybevalores para assim que um Nothingé encontrado, então é como um aborto imediato ou um retorno sem valor no meio de um cálculo.
Você poderia ter escrito talvez
Como eu disse antes, não há nada inerente ao Maybetipo que está embutido na sintaxe da linguagem ou no sistema de tempo de execução. Se Haskell não o forneceu por padrão, você mesmo poderia fornecer todas as suas funcionalidades! Na verdade, você mesmo poderia escrever novamente, com nomes diferentes, e obter a mesma funcionalidade.
Esperamos que você entenda o Maybetipo e seus construtores agora, mas se ainda houver alguma dúvida, me avise!
Maybeonde outras línguas usariamnullounil(com sórdidosNullPointerExceptions espreitando em cada esquina). Agora, outras linguagens também começam a usar essa construção: Scala asOption, e até mesmo Java 8 terá oOptionaltipo.