Closed darklight3it closed 6 years ago
Hi @darklight3it
Thanks so much for taking the time to write up this issue.
I'm not sure I agree with your assertion. Remember None
itself is not a monad, but Maybe
is. The monad law for left identity start with M.of(a)
, which for Maybe will always be a Some
because it is the only subclass that can contain a value.
For the second law, None.chain(M.of)
should alway return a None
, as m
is a None
.
Remember the f
in chain is a function from A => Maybe[B]
, so really None.chain(x => x + 2)
is non-sensical and wouldn't compile in a typed language. It would need to be None.chain(x => Some(x+2))
which should still return a None
.
A None Monad chained with a function that returns a non null/undefined value should return a Some.
This is not true according to any of the 3 monad laws. A None
can't turn into a Some
because there is no value to extract out of the None
to "chain" through.
Hopefully I've understood your issue correctly.
Thanks for your response, I need some insight on this issue. I'm making a typescript implementation of a Monad library just for fun and I'm facing the same issue.
Maybe i've found the incorrect example. Let's try with yours None.chain(x => Some(x+2))
.
//left part as you imagine
None.chain(x => Some(x+2)) = None()
//right part
f(null) = Some(null+2) = Some(2)
f(undefined) = Some(undefined + 2) = Some(NaN)
f(NaN) = Some(NaN +2) = Some(NaN)
The two side of the equation are different and the rule does not seem to value. This is because not every operation implying a null/undefined/NaN value return a null/undefined/NaN. Other implementation of the maybe seem to take into account that case. I suppose also that to make a complete Maybe monad you should check also for NaN (at least in javascript).
The specification is not clear if the (x => Some(x+2)) argument could be a valid one for a None. But if this argument is permitted it certainly breaks the Monad completeness.
I have a simple example that may help:
if you have a function const fn = x => Some(x+2)
and left side of our equation:
None().chain(fn)
Then you can be 100% sure that fn
will not be called at all, chain
will just return this
(the None created by None()
constructor).
Lambda passed as an argument to the chain
operator on Maybe
monad in Monet
(same with Maybe
in Haskell or Option
in Scala), will be just ignored - this is how fail-fast is implemented in this case.
Yes but this do not resolve my question. Is const fn = x => Some(x+2)
a valid value for a chain?
If it is returning None()
breaks the left identity law (at least in javascript where operation with null can return a valid value).
Probably in Haskell/Scala (i do not know them) this kind of operations are not permitted and return invalid value and the law still holds.
Sorry for the long discussion, but for me this is really interesting.
Yes const fn = x => Some(x+2)
is valid value.
And it doesn't break the left identity law.
A None Monad chained with a function that returns a non null/undefined value should return a Some.
Above statement is not true - None
monad chained
with anything should always return None
.
See M.of(a).chain(f)
--> M.of(a)
will always return Some<typeof a>
.
The only case that is tricky here is the fact that M.of(null)
(Some(null)
/ Maybe.of(null)
) will throw. That is because monet
version of Maybe was meant to overcome null
/ undefined
issues in JavaScript.
See also this discussion: https://github.com/monet/monet.js/issues/53 especially this comment: https://github.com/monet/monet.js/issues/53#issuecomment-212276496
@darklight3it - did above explanation help? Maybe there's still something I'm missing…
The three monadic laws (also specified in fantasyland) are the following (chain aka bind):
M.of(a).chain(f)
is equivalent tof(a)
(left identity)m.chain(M.of)
is equivalent tom
(right identity)m.chain(f).chain(g)
is equivalent tom.chain(x => f(x).chain(g))
(associativity)If you try the first test with a None() it should give you a error. In your code it gives:
A None Monad chained with a function that returns a non null/undefined value should return a Some.
You could correct this error in this way