I understand that with Option type, step 3 from c in SomeC(b) will be "skipped" due to NoneB(a) returns type of None.
//pseudo code
from a in SomeA(0) //returns Some<int>
from b in NoneB(a) //returns None
from c in SomeC(b) //returns Some<int>
select c //c is of None type
If I'm trying to combine Option with Writer. Is it possible to achieve the same "skipping" behaviour?
//pseudo code
from a in WriterSomeA(0) //returns Writer<Option<int>, string[]>
from _1 in Tell("Done A")
from b in WriterNoneBB(a) //returns None
from _2 in Tell("Done B")
from c in WriterSomeC(b)
from _3 in Tell("Done C")
select c
And should I be expecting c to be of type Writer<None<int>, string[]> as well as skipping step from c in WriterSomeC(b)?
I think you forgot to put in before each Tell in your pseudo code.
In a single LINQ query syntax expression, the monad after in always has to be the same. So if you had wanted to use both the Option and Task monads, then a solution would have been to use the OptionAsync monad, which combines those two monads into one.
As far as I know, Language Ext does not have a monad that combines Writer and Option, and I don't know of any other way to solve this problem. However, there might be some solution of which I am unaware.
Fixed the typo.
So what you are saying is, instead of trying to combine the 2 types / monads using some weird and possibly impossible custom Select/SelectMany, come up with just a single type / monad that does 2 things at the same time (i.e. skipping and logging).
I think you meant OptionAsync?
...instead of trying to combine the 2 types / monads using some weird and possibly impossible custom Select/SelectMany, come up with just a single type / monad that does 2 things at the same time (i.e. skipping and logging).
I think these are the same.
I what I meant was you can't do
from a in option
from b in writter
The type of the variables on the right side of in must be the same, like
from a in optionWritter1
from b in optionWritter2
I think you meant OptionAsync ?
Yep, just fixed that typo. Thanks :)
I what I meant was you can't do
from a in option from b in writter
I was thinking whether there's a custom SelectMany that I can write which translates between the 2 different types. Just a wild thought. But that's probably "hard coding" which is the same as creating a purposeful combined single type.
:)
@HistoricallyCorrect Mixing of monad types is a bad idea and special-case SelectMany implementations leads to real inference problems for the C# compiler. It would also wipe out the writer log for stages which don't support it (the Option stages).
However the Writer has an IsBottom state, which you could use for None:
```c#
public static Writer
where MonoidW : struct, Monoid
(default, default, true);
But some better advice might be to use the code-gen system for wrapping up the `RWS` monad (Reader/Writer/State):
```c#
[RWS(WriterMonoid: typeof(MSeq<string>), Env: typeof(Unit), State: typeof(Unit),
Constructor: "Pure", Fail: "WriterNone")]
public partial struct Subsys<T>
{
// This is here to wrap up the call to the generation of a single item `Seq`
public static Subsys<Unit> tell(string what) =>
tell(Seq1(what));
}
By making the Env and State into Unit you effectively have a Writer which is easier to use than the default one. So you can see that by using WriterNone it effectively gives you a short-cut out of the monad.
The Constructor and Fail parameters are used to give names to the constructor an failure functions.
You can then do this:
```c#
using static Subsys;
from a in Pure(0)
from _1 in tell("Done A")
from b in WriterNone
from _2 in tell("Done B")
from c in Pure(b)
from _3 in tell("Done C")
select c
``
I updated theReadera few weeks back to support better error handling, and will update theRWSto have a similar error handling mode in the next few days. So you'll be able to provide an [Error` type](https://github.com/louthy/language-ext/blob/master/LanguageExt.Core/Common/Error.cs#L6) that can take exceptions, strings, and error codes.