pub hkt Monoid { identity: T fn concat(first_item: A, second_item: A): T } pub hkt Monad { fn map(mapper: fn (item: A): B): T fn flat_map(mapper: fn (item: A): T): T } // Use this one! pub hkt Identity(a: A) { fn identity() = a } pub hkt Monoid(a: A) : Identity(a) { fn concat(other: Self) = Self(a + other.a) } pub hkt Monad1(a: A) { fn map(mapper: fn (from: A): B) = Self(mapper(a)) fn flat_map(mapper: fn (from: A): T) = Self(mapper(b)?) } pub hkt Monad2 : Monad2 { fn map_right(mapper: fn (right: B): B): T fn flat_map_right(mapper: fn (right: B): T): T fn fold_right(folder: fn (right: B): A): T } pub hkt Reader : Monad { impl fn map(mapper) = Self(mapper(self)) impl fn flat_map(mapper) = mapper(self)? fn bind(item: A): Self fn bind_from(item_producer: fn (): A): Self fn bind_from_map(item_mapper: fn (item: A): A): Self fn bind_from_flat_map(item_mapper: fn (item: A): T): Self fn ask(): A fn use(user: fn (item: A): T): Self } pub enum type Option : Monad1 { Some(item: T) { impl fn map(mapper) = Success(mapper(item)) impl fn flat_map(mapper) = mapper(item)? }, None { impl fn map = self impl fn flat_map = self } } pub enum type IO : Monad2 { Success(item: T) { impl fn map(mapper) = Success(mapper(item)) impl fn flat_map(mapper) = mapper(item)? impl fn map_right(mapper) = self impl fn flat_map_right(mapper) = self impl fn fold_right(folder) = self }. Failure(error: E) { impl fn map(mapper) = self impl fn flat_map(mapper) = self impl fn map_right(mapper) = Failure(mapper(error)) impl fn flat_map_right(mapper) = mapper(error)? impl fn fold_right(folder) = Success(folder(error)) } } // usage in a file interface decl pub fn open_file(name: String): FileReader> pub int File { name: String fn read_data(): IO fn close: IO } pub type FileReader : Reader> { fld io: IO impl fn bind(file) { io = Success(file) } impl fn bind_from(producer) { io = Success(producer()) } impl fn bind_from_map(mapper) { io = Success(mapper(io?)) } impl fn bind_from_flat_map(flat_mapper) { io = Success(flat_mapper(io?)?) } impl fn ask() = io? impl fn use(user) = { user(io?) self } } // some other file open_file('test.txt') // FileReader> .flat_map { f -> f.read_data() } // FileReader> .use { f -> f.close() } // FileReader> .ask()? // String