I checked the rules, but forgot to post the explanation here.

You are right that it is not quite as simple as returning the innermost/outermost client - but it is close.

The main problem in this case is actually in something else - in the

**construct** function itself. The

**construct** function can not return

**construct(a) = a×b** because it would need to get

**b** from somewhere.

A cartesian product (a pair) is a monad when the 'other type' is a monoid. In this case, we have the main type

**T** and the context type

**socket***.

The

**socket*** is a monoid similar to Maybe/optional:

mempty = nullptr
mappend(x, y) := x ? x : y // leftmost non-empty value (not the only
// solution for mappend, but the easiest)

The construct function needs to return the value coupled with a

`nullptr` client (

**mempty**).

construct(a) {
return { a, nullptr };
}
mbind({ a, client1 }, f) := {
auto [ b, client2 ] = f(a);
return { b, mappend(client1, client2) };
}

(it is quite tedious to write this in pseudo-C++17 syntax

)

Then the identity laws are satisfied:

mbind(construct(a), f)
== mbind({a, nullptr}, f)
// ... f(a) returns {b, client}, mbind mappends nullptr to client
== { b, client }
== f(a)
mbind({ a, client }, construct)
// ... construct(a) gives {a, nullptr}, mbind mappends
== { a, client }

As for this particular example, you are right, functor with an

`apply_for_client` function would be sufficient.