There is a given function, that is fixed and must not be changed:
const validate = v => v === "fred" ? "Y" : undefined
Now, because I would like to be functional and would like to avoid null-checks I've decided to use Maybe
(ramda-fantasy
) for validation function:
const vv = val => Maybe(val).map(v=> validate(v)).getOrElse("N")
vv
should return Y
if it's called with "fred"
otherwise N
.
vv(null)
returnsN
-> OKvv("fred")
returnsY
-> OKvv("ding")
returnsundefined
-> wrong, expectedN
The problem is, that Maybe.map
always returns Just
, that I do not understand (because I'm just learning it). For me I would be beneficial if this function would behave in similar way to Maybe(val)
that returns None
or Just
.
I have two question:
- Why
Maybe.map
does not handle null/undefined? - How to rewrite
vv
that it would return expected values in all three cases?
EDIT: I would like to explain why validate should not be changed: it's just simple example of function coming from external library. I wanted to see how easy/hard is to integrate such libraries into functional programming. So is not about string operations, just about streaming values when at some point it evaluates to null.
EDIT2:
This solves my problem:
Either.ofNullable = Either.prototype.ofNullable = function (value) {
return value == null ? Either.Left("is null") : Either.Right(value);
};
EDIT3: I've implemented my own Either with missing functionality: https://github.com/maciejmiklas/functional-ts/blob/main/src/either.ts
Note: Ramda Fantasy is no longer maintained. The team recommends that you use other implementations of these concepts.
But we can still answer this question, as it's likely to be true of any reasonable
Maybe
implementationBasically, that's not how Maybe is designed to work. The idea is that you can have a Just holding absolutely any value. That includes the values
null
andundefined
.Ramda added a convenience constructor,
Maybe (val)
, which turns intoJust (val)
if val is not a nil value, and intoNothing ()
if it is. But that doesn't mean that you cannot create aJust (null)
. The main construction technique is to use the staticMaybe .of
. And you can note thatSo we're probably not going to make that technique work. We couldn't just
map
such an existingvalidate
over ourMaybe
and expect it to work. We could, however, work with a version like this:Here, we still have one problem.
Maybe ('fred') .map (validate)
yieldsJust (Just ('Y'))
. We have extra nesting. But this is exactly whatchain
is for. It removes such an additional level, so thatMaybe ('fred') .chain (validate)
yieldsJust ('Y')
. We can then use it like this: