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)
returns N
-> OKvv("fred")
returns Y
-> OKvv("ding")
returns undefined
-> wrong, expected N
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:
Maybe.map
does not handle null/undefined?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
implementation
Basically, 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
and undefined
.
Ramda added a convenience constructor, Maybe (val)
, which turns into Just (val)
if val is not a nil value, and into Nothing ()
if it is. But that doesn't mean that you cannot create a Just (null)
. The main construction technique is to use the static Maybe .of
. And you can note that
Maybe (null) //=> Nothing ()
Maybe.of (null) //=> Just (null)
So we're probably not going to make that technique work. We couldn't just map
such an existing validate
over our Maybe
and expect it to work. We could, however, work with a version like this:
const validate = v => v === "fred" ? Just ("Y") : Nothing ()
Here, we still have one problem. Maybe ('fred') .map (validate)
yields Just (Just ('Y'))
. We have extra nesting. But this is exactly what chain
is for. It removes such an additional level, so that Maybe ('fred') .chain (validate)
yields Just ('Y')
. We can then use it like this:
const validate = v => v === "fred" ? Just ("Y") : Nothing ()
const vv = val => Maybe (val) .chain (validate) .getOrElse ('N')
console .log ([
vv (null), // 'N'
vv ('fred'), // 'Y'
vv ('ding') // 'N'
])