Skip to content

Instantly share code, notes, and snippets.

@idugalic
Last active April 29, 2025 16:02
Show Gist options
  • Save idugalic/bc7b9c42e170689aa8e21afbdfbf28af to your computer and use it in GitHub Desktop.
Save idugalic/bc7b9c42e170689aa8e21afbdfbf28af to your computer and use it in GitHub Desktop.
Information Systems
package com.fraktalio
// ##################################################
// ##################################################
// Information System - encoded in Kotlin type system
// ##################################################
// ##################################################
/**
* A formalization of the traditional/state stored information system.
* State-Stored systems are traditional systems that are only storing the current state by overwriting the previous state in the storage.
* A function that takes command/request and `current` state of the system to produce `new` state of the system as a result.
*
* @param Command an intent to change the state of the system
* @param State a state of the system
*/
typealias StateStoredSystem<Command, State> = (Command, State) -> State
/**
* A formalization of the event-sourced information system.
* Event-Sourced systems are storing the events in immutable storage by only appending.
* A function that takes command/request and `current` state (sequence of Events) of the system to produce `new` state (sequence of Events) of the system as a result.
*
* @param Command an intent to change the state of the system
* @param Event a state change itself
*/
typealias EventSourcedSystem<Command, Event> = (Command, Sequence<Event>) -> Sequence<Event>
/**
* A formalization of any information system.
* This encoding captures both event-sourced and state-stored systems, providing a unified model for different architectural styles.
*/
typealias System<Command, State, Event> = Triple<
(Command, State) -> Sequence<Event>, // 1. decide
(State, Event) -> State, // 2. evolve
() -> State // 3. initial state
>
/**
* Mapping general system into traditional/state-stored system
*/
fun <Command, State, Event> System<Command, State, Event>.asStateStoredSystem(): StateStoredSystem<Command, State> =
{ command, state ->
first(command, state).fold<Event, State>(third()) { state, event -> second(state, event) }
}
/**
* Mapping general system into event-sourced system
*/
fun <Command, State, Event> System<Command, State, Event>.asEventSourcedSystem(): EventSourcedSystem<Command, Event> =
{ command, events ->
first(command, events.fold<Event, State>(third()) { state, event -> second(state, event) })
}
// ######################
// Functors of the System
// ######################
// These functors provide several key benefits:
// - Type Safety: Transformations are checked at compile-time, reducing runtime errors.
// - Composability: Systems can be transformed and composed without breaking their internal structure.
// - Flexibility: Easy adaptation of existing systems to work with new types or requirements.
// ######################
// Map system that can handle command(s) of type `Command` into a system that can handle command(s) of type `Command2`
inline fun <Command, Command2, State, Event> System<Command, State, Event>.mapCommand(crossinline f: (Command2) -> Command): System<Command2, State, Event> =
Triple(
{ command2, state -> first(f(command2), state) }, // Transform Command2 to Command using f() in decide function
second, // Keep evolve function as is
third // Keep initial state as is
)
// Map system that can publish event(s) of type `Event` into a system that can publish event(s) of type `Event2`
inline fun <Command, State, Event, Event2> System<Command, State, Event>.mapEvent(
crossinline fl: (Event2) -> Event,
crossinline fr: (Event) -> Event2
): System<Command, State, Event2> =
Triple(
{ command, state -> first(command, state).map { fr(it) } },
{ state, event2 -> second(state, fl(event2)) },
third
)
// Map system that can manage state(s) of type `State` into a system that can manage state(s) of type `State2`
inline fun <Command, State, State2, Event> System<Command, State, Event>.mapState(
crossinline fl: (State2) -> State,
crossinline fr: (State) -> State2
): System<Command, State2, Event> =
Triple(
{ command, state2 -> first(command, fl(state2)) },
{ state2, event -> fr(second(fl(state2), event)) },
{ fr(third()) }
)
fun main() {
println("https://fraktalio.com/fmodel/")
}
@ismasan
Copy link

ismasan commented Apr 29, 2025

This is lovely! ❤️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment