pub hkt Functor[Self] { fn map(f: fn (t: &T) -> U) -> Self // &self implied } pub hkt Applicative[Self] : Functor[Self] { static fn lift(t: T) -> Self // static: no implicit self parameter fn apply(us: &Self) -> Self where T : fn (u: &U) -> V } pub hkt Monad[Self] : Applicative[Self] { fn flatMap(f: fn (t: &T) -> Self) -> Self } // Here, T is a separate type parameter from the container's inner type // The container's inner type is ..., which can be anything, of any number of parameters pub hkt Into[Self<...>, T] { cons fn into() -> T // consumes self } pub hkt Zero[Self] { static fn zero() -> Self } pub int Iterable : Into[Self, Iterator] { /** * Iterator for references to contained item(s). */ ref fn iter() -> Iterator<&T> // ref indicates return value cannot outlive self def cons fn intoIter() = Into[Self, Iterator].into() } pub type Iterator = () -> Option pub int Exception { message: Option } pub enum Option : Monad[Self] { Some(T), None; class EmptyOptionException(message: Option = Empty) : Exception // cons implies that self is consumed (like Rust `self: Self`) cons fn unwrap() -> T = self is Some(t) ? t : throw EmptyOptionException() cons fn expect(message: String) -> T { if let Some(t) = self { t } else { throw EmptyOptionException(message) } } cons fn unwrapOr(self, other: T) -> T = self is Some(t) ? t : other cons fn unwrapOrElse(self, f: fn () -> T) = self is Some(t) ? t : f() impl Monad[Self] { fn map(f: fn (t: &T) -> U) -> Self = self is Some(t) ? Some(f(t)) : Empty static fn lift(t: T) -> Self = Some(t) fn apply(us: &Self) -> Self where T : fn (u: U) -> V = self is Some(f) && us is Some(u) ? Some(f(u)) : Empty // note in above that `f` is `&fn (u: U) -> V`, but `f()` is sugar for `(*f)()` fn flatMap(f: fn (t: &T) -> Self) -> Self = self is Some(t) ? f(t) : Empty } } pub class OptionT[M](fld o: M>) : Monad[Self[M]] where M : Monad[Option] { pub fn intoInner() -> M> = Into[Self[M], M>].into(self) pub fn flatMapInner(f: fn (t: &T) -> M>) -> Self[M] { OptionT( Monad[M].flatMap(o) { ts: &Option -> ts is Some(t) ? f(t) : None } ) } impl Monad[Self[M]] { fn map(f: fn (t: &T) -> U) -> Self[M] { OptionT( Monad[M].map(o) { // implicit `it` parameter is `&Option` // When destructured, `t` is `&T` it is Some(t) ? Some(f(t)) : None } ) } static fn lift(t: T) -> Self[M] = OptionT(Monad[M].lift(Some(t))) fn apply(us: &Self[M]) -> Self[M] where T : fn (u: &U) -> V { OptionT( Monad[M].flatMap(o) { fOpt: &Option V> -> fOpt is Some(f) ? Monad[M].map(us.o) { uOpt: &Option -> uOpt is Some(u) ? Some(f(u)) : None } : Monad[M].lift(None) } ) } fn flatMap(f: fn (t: &T) -> Self[M]) -> Self[M] { OptionT( Monad[M].flatMap(o) { it is Some(t) ? f(t).o : Monad[M].lift(None) } ) } } impl Into, M>> { cons fn into() -> M> = o } } pub int List : Iterable + Zero[Self] + Monad[Self] { mut fn add(t: T) -> Void // mut implies &mut self // def = default // mut = &mut self // op = operator overload // << = left shift def mut op << (t: T) -> Void = add(t) ref fn get(i: Int) -> Option<&T> // ref implies that the returned object cannot outlive self // implied &self // Alternative syntax for get(i) definition: // fn get(i: Int) -> Option<&T> ref self def ref op [] (i: Int) -> Option<&T> = get(i) impl Monad[Self] { fn map(f: fn (t: &T) -> U) -> Self { let out: List = Zero[Self].zero() for item in self { // item is &T out << f(item) } out } static fn lift(t: T) -> Self = ArrayList(t) fn apply(us: &Self) -> Self where T : fn (u: &U) -> V { let out: List = Zero[Self].zero() for f in self { // f is &fn (u: &U) -> V for u in us { // u is &&u out << f(*u) // syntax sugar for out.add((*f)(*u)) } } out } fn flatMap(f: fn (t: &T) -> Self) -> Self { let out: List = Zero[Self].zero() for t in self { // t is &T for u in Into[Self, Iterator].into(f(t)) { // u is U out << u // out take ownership of u } } out } } } pub class LinkedList : List { // inner classes are static by default class Node(data: T) { mut next: Option> } mut fld head: Option> impl mut fn add(t: T) -> Void { match head { None => { head = Some(Node(t)) } Some => { let mut current: &Option> = &head while let Some(next) = ¤t?.next { // get a reference to current.next, or None if either are none current = next } current.next = Some(Node(t)) } } } impl ref fn get(index: Int) -> Option<&T> { let mut current: &Option> = &head let mut currentIndex = 0 while currentIndex < index { if let Some(next) = ¤t?.next { currentIndex++ current = next } else { break } } current is Some(node) ? Some(&node.data) : None } impl ref fn iter() -> Iterator<&T> { let mut current: &Option> = &head () -> { if let Some(node) = current { let data: &T = &node.data current = &node.next Some(data) } else { None } } } impl Into[Self, Iterator] { cons fn into() -> Iterator { let mut current: Option> = take(head) // take replaces head with None return () -> { let result = current current = current?.next result is Some(node) ? Some(node.data) : None } } } impl Zero[Self] { static fn zero() -> Self = LinkedList() } } fn optionTListDemo() { let oddsOnly: List> = [ Some(1), None, Some(3), None, Some(5) ] let liftedOddsOnly: OptionT[]<> = OptionT(oddsOnly) let mapped = liftedOddsOnly .flatMapInner { [Some(it), Some(it + 1)] } .map { "Value: ${it.toString()}" } for o in mapped.intoInner() { if o is Some(s) { println s } } }