Reputation: 32162
Through composition in my C# code I've ended up with a type
IObservable<Maybe<IObservable<T>>> events;
where Maybe is the option monad and IObservable is the reactive monad.
Now I want to transform this into
IObservable<Maybe<T>> flatEvents;
which I think expresses pretty much the same thing. Note I want to preserve the "nothing to see" event embodied by the maybe. I don't want to flatten it out completely so that I only see events when an instance of T is available.
After a bit of trial and error I found I can do the transformation via
var flatEvents = events
.Select(p=>p.Select(q=>q.Select(v=>v.ToMaybe()))
.Else(Observable.Return(None<T>.Default)))
.Switch();
where None<T>.Default
returns a Maybe<T>
which is empty.
T Maybe<T>.Else(T v)
extracts the contained value in the option monad and if there is not one then provides an alternative.
Considering that naming things is the hardest thing is CS I'm looking for a name for this flattening operator. I'm not a haskell programmer but I'm sure I haven't invented anything here and this is some kind of common projection. Is there a name for this?
Upvotes: 0
Views: 130
Reputation: 137937
I find it easier to work out what your design is by purely considering the types, independent of any particular monad.
You want a function of type:
:: Observable (Maybe (Observable a))
->
Observable (Maybe a)
where Maybe is a monad and Observable is a monad.
Since monads are a general interface, we really have:
:: (Monad m, Monad t) => m (t (m a)) -> m (t a)
From this type we can see it is a kind of join distributed over the
inner monad m
.
Some related types:
join :: Monad m => m (m a) -> m a
sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)
In fact, it looks very much like fmap sequence over the inner component, followed
by a join -- which has almost the correct type, assuming t
is in Traversable (as
well as Monad):
> :t join . fmap T.sequence
:: (Monad m, Functor m, Traversable t)
=> m (t (m a)) -> m (t a)
So there's our type. m (t (m a))
to m (t a)
. Perfect.
So if you really need to name this, it would be joinSequence or something. But perhaps it doesn't need a name.
Upvotes: 5