// Use this one! pub int Unit pub hkt Identity { fn identity() = Self } pub int Addable> { fn op+(other: T): T } pub hkt Monoid>(a: A) : Identity { fn concat(other: Self) = Self(a + other.a) } pub hkt Monad1(item: A) { fn map(m: fn (from: A): B) = item is A ? Self(m(item)) : self fn flat_map(m: fn (from: A): T) = item is A ? m(item) : self } pub hkt Monad2(item: A | B) : Monad1(item is A ? item : Unit) { fn map_right(m: fn (right: B): B) = item is B ? Self(m(item)) : self fn flat_map_right(m: fn (right: B): Self) = item is B ? m(item) : self fn fold_right(f: fn (right: B): A) = item is B ? Self(f(item)) : self } pub hkt Reader2(readable: R, item: A, other: B) : Monad2(item) { fn read(reader: fn (readable: R): A) = Self(readable, reader(readable), other) fn use(user: fn (readable: R): Unit) = Self(readable, user(readable), other) } pub enum type Option : Monad1 { Some(item), None } pub enum type IO : Monad2 { Success(item: T), Failure(error: E) } // usage in a file interface pub fn open_file(name: String): FileReader { try { let file: LuaObject = lua {% fs.open(${name}) %} return Success( File { name, impl fn read_data() { lua {% ${file}.readAll() %} } impl fn close() { lua {% ${file}.close() %} } }, Unit ) } catch (e: LuaError) { return Failure(e) } } pub enum type FileReader : Reader2 { Success(file: File, result: R) : Super(file, result, Unit), Failure(error: E) : Super(file, Unit, error) } pub int File { name: String fn read_data(): String fn close() } // usage in a main file, perhaps match open_file('test.txt') .read { f -> f.read_data() } .map { data -> data.length() } { Success(file, length) => { f.close() println(result) }, Failure(error) => { println(error.message) } }