0

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 -> OK
  • vv("fred") returns Y -> OK
  • vv("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:

  1. Why Maybe.map does not handle null/undefined?
  2. 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

Maciej Miklas
  • 3,305
  • 4
  • 27
  • 52

1 Answers1

2

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'
])
Scott Sauyet
  • 49,207
  • 4
  • 49
  • 103
  • OP did ask to keep `validate` in tact. Does `val => Maybe(validate(val)).getOrElse("N")` work? Nice primer on Maybe. – Mulan Oct 17 '20 at 13:01
  • @Thankyou: While yes that would work, there seems no reason to use `Maybe` for that. Simply `(v, r = validate2(v)) => r == 'Y' ? 'Y' : 'N'` would be fine. Wrapping something in a Maybe only to unwrap it in the same expression doesn't add anything useful. I suppose I should have also suggested something like `(val) => Maybe(val).map(validate).getOrElse('N') || 'N'` but I assumed that was obvious, and doesn't really help one learn about `Maybe`. – Scott Sauyet Oct 17 '20 at 17:52
  • @Thankyou: Or I suppose we could get even stranger and use something like `(val) => Maybe(Maybe(val).map(validate).getOrElse('N')).getOrElse('N')`. But I wouldn't be happy with that. – Scott Sauyet Oct 17 '20 at 17:56
  • My original understanding was that `validate` was an imported function and the OP wanted to bring it into the `Maybe` domain – Mulan Oct 17 '20 at 20:21
  • @Thankyou: Yes, I get that, but I was assuming that the goal was to use it somehow together with `Maybe(val)`. Simply introducing a `Maybe` in the context of a `String -> String` function makes little sense to me; there are plenty of ways to do that better. But I don't think there's a *good* way to do what I think the OP wants, which is to combine `Just(String) | Nothing()` with `String -> String | Undefined` to get `String ('Y'|'N')`. The `undefined` (perhaps unfortunately) is a value in the language, and can be contained in a `Just`. But it's possible that I misunderstand entirely. – Scott Sauyet Oct 17 '20 at 21:57