// Path: core/src/main/java/eventsrc4j/WStreamAction.java
// @FunctionalInterface
// public interface WStreamAction<K, S, E, R> {
// 
//   /**
//    * Monadic WStreamAction algebra, that is also a StreamAction algebra
//    *
//    * @param <R> action result type.
//    * @param <X> interpreted action result type (eg. wrapped in a container).
//    */
//   interface Algebra<K, S, E, R, X> extends StreamAction.Algebra<K, S, E, R, X> {
// 
//     X Write(Option<S> expectedSeq, Instant time, Iterable<E> events, TypeEq<WriteResult<K, S, E>, R> resultType);
// 
//     <Q> X BindW(WStreamAction<K, S, E, Q> action, F<Q, WStreamAction<K, S, E, R>> function);
// 
//     // We derive implementation of monadic operations of the StreamAction algebra in term of this WStreamAction algebra:
//     @Override
//     default <Q> X Bind(StreamAction<K, S, E, Q> action,
//         F<Q, StreamAction<K, S, E, R>> function) {
//       return BindW(action::eval, compose(a -> a::eval, function));
//     }
//   }
// 
//   interface Factory<K, S, E> {
// 
//     default WStreamAction<K, S, E, WriteResult<K, S, E>> WriteEvents(Option<S> expectedSeq, Instant time,
//         Iterable<E> events) {
//       return new WStreamAction<K, S, E, WriteResult<K, S, E>>() {
//         @Override public <X> X eval(Algebra<K, S, E, WriteResult<K, S, E>, X> interpreter) {
//           return interpreter.Write(expectedSeq, time, events, TypeEq.refl());
//         }
//       };
//     }
// 
// 
//     default StreamAction.Factory<K, S, E> streamActionFactory() {
//       return StreamAction.factory();
//     }
// 
//     default <R> WStreamAction<K, S, E, R> ReadEventStream(Option<S> fromSeq,
//         Fold<Event<K, S, E>, R> streamFold) {
//       return streamActionFactory().ReadEventStream(fromSeq, streamFold)::eval;
//     }
// 
//     default WStreamAction<K, S, E, Option<Event<K, S, E>>> GetLatestEvent() {
//       return streamActionFactory().GetLatestEvent()::eval;
//     }
// 
//     default <R> WStreamAction<K, S, E, R> Pure(R value) {
//       return streamActionFactory().Pure(value)::eval;
//     }
//   }
// 
//   static <K, S, E> Factory<K, S, E> factory() {
//     return new Factory<K, S, E>() {
//     };
//   }
// 
//   <X> X eval(Algebra<K, S, E, R, X> interpreter);
// 
//   default <Q> WStreamAction<K, S, E, Q> map(F<R, Q> f) {
//     return bind(r -> WStreamAction.<K, S, E>factory().Pure(f.f(r))::eval);
//   }
// 
//   default <Q> WStreamAction<K, S, E, Q> bind(F<R, WStreamAction<K, S, E, Q>> f) {
//     return new WStreamAction<K, S, E, Q>() {
//       @Override public <X> X eval(Algebra<K, S, E, Q, X> interpreter) {
//         return interpreter.BindW(WStreamAction.this, f);
//       }
//     };
//   }
// }
// 
// Path: core/src/main/java/eventsrc4j/WriteResult.java
// @data
// @Derive({})
// public abstract class WriteResult<K, S, E> {
// 
//   WriteResult() {
//   }
// 
//   public interface Cases<K, S, E, X> {
//     X Success(List<Event<K, S, E>> events);
// 
//     X DuplicateEventSeq();
//   }
// 
//   public abstract <X> X match(Cases<K, S, E, X> cases);
// 
//   public final Option<List<Event<K, S, E>>> events() {
//     return getEvents(this);
//   }
// 
//   @Override
//   public abstract String toString();
// 
//   @Override
//   public abstract boolean equals(Object obj);
// 
//   @Override
//   public abstract int hashCode();
// 
// }


import eventsrc4j.WStreamAction;
import eventsrc4j.WriteResult;
import fj.data.Option;
import java.time.Instant;
package eventsrc4j.io;


/**
 * A stream of events, that can be read and written into.
 *
 * @param <K> events key type.
 * @param <S> sequence used for ordering events in the stream.
 * @param <E> concrete domain events type.
 */
public interface WritableEventStream<K, S, E> extends EventStream<K, S, E> {

  /**
   * Save the given events at the end of the stream, if at expected sequence.
   *
   * @param expectedSeq expected last saved sequence of the stream, or empty if the stream is
   * expected to be empty.
   * @param time timestamp of the events to save.
   * @param events a list of events to save in the stream.
   * @return an IO action producing the result of the write; either successful or indicating an
   * optimistic concurrency error (duplicated sequence).
   */
  IO<WriteResult<K, S, E>> write(Option<S> expectedSeq, Instant time, Iterable<E> events);

// Path: core/src/main/java/eventsrc4j/WStreamAction.java
// @FunctionalInterface
// public interface WStreamAction<K, S, E, R> {
// 
//   /**
//    * Monadic WStreamAction algebra, that is also a StreamAction algebra
//    *
//    * @param <R> action result type.
//    * @param <X> interpreted action result type (eg. wrapped in a container).
//    */
//   interface Algebra<K, S, E, R, X> extends StreamAction.Algebra<K, S, E, R, X> {
// 
//     X Write(Option<S> expectedSeq, Instant time, Iterable<E> events, TypeEq<WriteResult<K, S, E>, R> resultType);
// 
//     <Q> X BindW(WStreamAction<K, S, E, Q> action, F<Q, WStreamAction<K, S, E, R>> function);
// 
//     // We derive implementation of monadic operations of the StreamAction algebra in term of this WStreamAction algebra:
//     @Override
//     default <Q> X Bind(StreamAction<K, S, E, Q> action,
//         F<Q, StreamAction<K, S, E, R>> function) {
//       return BindW(action::eval, compose(a -> a::eval, function));
//     }
//   }
// 
//   interface Factory<K, S, E> {
// 
//     default WStreamAction<K, S, E, WriteResult<K, S, E>> WriteEvents(Option<S> expectedSeq, Instant time,
//         Iterable<E> events) {
//       return new WStreamAction<K, S, E, WriteResult<K, S, E>>() {
//         @Override public <X> X eval(Algebra<K, S, E, WriteResult<K, S, E>, X> interpreter) {
//           return interpreter.Write(expectedSeq, time, events, TypeEq.refl());
//         }
//       };
//     }
// 
// 
//     default StreamAction.Factory<K, S, E> streamActionFactory() {
//       return StreamAction.factory();
//     }
// 
//     default <R> WStreamAction<K, S, E, R> ReadEventStream(Option<S> fromSeq,
//         Fold<Event<K, S, E>, R> streamFold) {
//       return streamActionFactory().ReadEventStream(fromSeq, streamFold)::eval;
//     }
// 
//     default WStreamAction<K, S, E, Option<Event<K, S, E>>> GetLatestEvent() {
//       return streamActionFactory().GetLatestEvent()::eval;
//     }
// 
//     default <R> WStreamAction<K, S, E, R> Pure(R value) {
//       return streamActionFactory().Pure(value)::eval;
//     }
//   }
// 
//   static <K, S, E> Factory<K, S, E> factory() {
//     return new Factory<K, S, E>() {
//     };
//   }
// 
//   <X> X eval(Algebra<K, S, E, R, X> interpreter);
// 
//   default <Q> WStreamAction<K, S, E, Q> map(F<R, Q> f) {
//     return bind(r -> WStreamAction.<K, S, E>factory().Pure(f.f(r))::eval);
//   }
// 
//   default <Q> WStreamAction<K, S, E, Q> bind(F<R, WStreamAction<K, S, E, Q>> f) {
//     return new WStreamAction<K, S, E, Q>() {
//       @Override public <X> X eval(Algebra<K, S, E, Q, X> interpreter) {
//         return interpreter.BindW(WStreamAction.this, f);
//       }
//     };
//   }
// }
// 
// Path: core/src/main/java/eventsrc4j/WriteResult.java
// @data
// @Derive({})
// public abstract class WriteResult<K, S, E> {
// 
//   WriteResult() {
//   }
// 
//   public interface Cases<K, S, E, X> {
//     X Success(List<Event<K, S, E>> events);
// 
//     X DuplicateEventSeq();
//   }
// 
//   public abstract <X> X match(Cases<K, S, E, X> cases);
// 
//   public final Option<List<Event<K, S, E>>> events() {
//     return getEvents(this);
//   }
// 
//   @Override
//   public abstract String toString();
// 
//   @Override
//   public abstract boolean equals(Object obj);
// 
//   @Override
//   public abstract int hashCode();
// 
// }


// Path: core/src/main/java/eventsrc4j/io/WritableEventStream.java
import eventsrc4j.WStreamAction;
import eventsrc4j.WriteResult;
import fj.data.Option;
import java.time.Instant;

package eventsrc4j.io;


/**
 * A stream of events, that can be read and written into.
 *
 * @param <K> events key type.
 * @param <S> sequence used for ordering events in the stream.
 * @param <E> concrete domain events type.
 */
public interface WritableEventStream<K, S, E> extends EventStream<K, S, E> {

  /**
   * Save the given events at the end of the stream, if at expected sequence.
   *
   * @param expectedSeq expected last saved sequence of the stream, or empty if the stream is
   * expected to be empty.
   * @param time timestamp of the events to save.
   * @param events a list of events to save in the stream.
   * @return an IO action producing the result of the write; either successful or indicating an
   * optimistic concurrency error (duplicated sequence).
   */
  IO<WriteResult<K, S, E>> write(Option<S> expectedSeq, Instant time, Iterable<E> events);

  default <R> IO<R> evalWAction(WStreamAction<K, S, E, R> action) {