It is exceptionally difficult to come up with a compelling valuable use for a Maybe monad in Raku. Monads are most useful in languages that don't have exceptions and/or only allow a single point of entry/exit from a subroutine.
There are very good reasons to have those restrictions. It makes it much less complex to reason about a programs correctness and actually prove that a program is correct, but those restrictions also lead to oddities like Monads, just as a way to work around those restrictions.
The task description asks for two functions that take an Int and return a Maybe Int or Maybe Str, but those distinctions are nearly meaningless in Raku. See below.
my $monad = <42>;say'Is $monad an Int?: ', $monad ~~ Int;say'Is $monad a Str?: ', $monad ~~ Str;say'Wait, what? What exactly is $monad?: ', $monad.^name;
Output:
Is $monad an Int?: True
Is $monad a Str?: True
Wait, what? What exactly is $monad?: IntStr
$monad is both an Int and a Str. It exists in a sort-of quantum state where what-it-is depends on how-it-is-used. Bolting on some 'Monad' type to do this will only remove functionality that Raku already has.
Ok, say you have a situation where you absolutely do not want an incalculable value to halt processing. (In a web process perhaps.) In that case, it might be useful to subvert the normal exception handler and just return a "Nothing" type. Any routine that needs to be able to handle a Nothing type will need to be informed of it, but for the most part, that just means adding a multi-dispatch candidate.
# Build a Nothing type. When treated as a string it returns the string 'Nothing'.# When treated as a Numeric, returns the value 'Nil'.class NOTHING { method Str { 'Nothing' } method Numeric { Nil }}# A generic instance of a Nothing type.my \Nothing = NOTHING.new;# A reimplementation of the square-root function. Could just use the CORE one# but this more fully shows how multi-dispatch candidates are added.# Handle positive numbers & 0multi root (Numeric $n where * >= 0) { $n.sqrt }# Handle Negative numbers (Complex number handling is built in.)multi root (Numeric $n where * < 0) { $n.Complex.sqrt }# Else return Nothingmulti root ($n) { Nothing }# Handle numbers > 0multi ln (Real $n where * > 0) { log $n, e }# Else return Nothingmulti ln ($n) { Nothing }# Handle fraction where the denominator != 0multi recip (Numeric $n where * != 0) { 1/$n }# Else return Nothingmulti recip ($n) { Nothing }# Helper formatting routinesubcenter ($s) {my $pad = 21 - $s.Str.chars;' ' x ($pad / 2).floor ~ $s ~ ' ' x ($pad / 2).ceiling;}# Display the "number" the reciprocal, the root, natural log and the 3 functions# composed together.put ('"Number"', 'Reciprocal', 'Square root', 'Natural log', 'Composed')».¢er;# Note how it handles the last two "values". The string 'WAT' is not numeric at# all; but Ethiopic number 30, times vulgar fraction 1/7, is.put ($_, .&recip, .&root, .&ln, .&(&ln o &root o &recip) )».¢erfor -2, -1, -0.5, 0, exp(-1), 1, 2, exp(1), 3, 4, 5, 'WAT', ፴ × ⅐;