261 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			261 lines
		
	
	
		
			7.5 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
pub hkt Functor[Self<T>] {
 | 
						|
    fn <U> map(f: fn (t: &T) -> U) -> Self<U> // &self implied
 | 
						|
}
 | 
						|
 | 
						|
pub hkt Applicative[Self<T>] : Functor[Self<T>] {
 | 
						|
    static fn lift(t: T) -> Self<T> // static: no implicit self parameter
 | 
						|
    fn <U, V> apply(us: &Self<U>) -> Self<V> where T : fn (u: &U) -> V
 | 
						|
}
 | 
						|
 | 
						|
pub hkt Monad[Self<T>] : Applicative[Self<T>] {
 | 
						|
    fn <U> flatMap(f: fn (t: &T) -> Self<U>) -> Self<U>
 | 
						|
}
 | 
						|
 | 
						|
// 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<T>] {
 | 
						|
    static fn zero() -> Self<T>
 | 
						|
}
 | 
						|
 | 
						|
pub int Iterable<T> : Into[Self<T>, Iterator<T>] {
 | 
						|
    /**
 | 
						|
     * 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<T>, Iterator<T>].into()
 | 
						|
}
 | 
						|
 | 
						|
pub type Iterator<T> = () -> Option<T>
 | 
						|
 | 
						|
pub int Exception {
 | 
						|
    message: Option<String>
 | 
						|
}
 | 
						|
 | 
						|
pub enum Option<T> : Monad[Self<T>] {
 | 
						|
    Some(T),
 | 
						|
    None;
 | 
						|
 | 
						|
    class EmptyOptionException(message: Option<String> = 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<T>] {
 | 
						|
        fn <U> map(f: fn (t: &T) -> U) -> Self<U> = self is Some(t) ? Some(f(t)) : Empty
 | 
						|
 | 
						|
        static fn lift(t: T) -> Self<T> = Some(t)
 | 
						|
 | 
						|
        fn <U, V> apply(us: &Self<U>) -> Self<V> 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 <U> flatMap(f: fn (t: &T) -> Self<U>) -> Self<U> = self is Some(t) ? f(t) : Empty
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
pub class OptionT[M]<T>(fld o: M<Option<T>>) : Monad[Self[M]<T>] where M : Monad[Option<T>] {
 | 
						|
    pub fn intoInner() -> M<Option<T>> = Into[Self[M]<T>, M<Option<T>>].into(self)
 | 
						|
 | 
						|
    pub fn <U> flatMapInner(f: fn (t: &T) -> M<Option<U>>) -> Self[M]<U> {
 | 
						|
        OptionT(
 | 
						|
            Monad[M].flatMap(o) { ts: &Option<T> ->
 | 
						|
                ts is Some(t) ? f(t) : None
 | 
						|
            }
 | 
						|
        )
 | 
						|
    }
 | 
						|
 | 
						|
    impl Monad[Self[M]<T>] {
 | 
						|
        fn <U> map(f: fn (t: &T) -> U) -> Self[M]<U> {
 | 
						|
            OptionT(
 | 
						|
                    Monad[M].map(o) {
 | 
						|
                        // implicit `it` parameter is `&Option<T>`
 | 
						|
                        // When destructured, `t` is `&T`
 | 
						|
                        it is Some(t) ? Some(f(t)) : None
 | 
						|
                    }
 | 
						|
            )
 | 
						|
        }
 | 
						|
 | 
						|
        static fn lift(t: T) -> Self[M]<T> = OptionT(Monad[M].lift(Some(t)))
 | 
						|
 | 
						|
        fn <U, V> apply(us: &Self[M]<U>) -> Self[M]<V> where T : fn (u: &U) -> V {
 | 
						|
            OptionT(
 | 
						|
                    Monad[M].flatMap(o) { fOpt: &Option<fn (u: &U) -> V> ->
 | 
						|
                        fOpt is Some(f)
 | 
						|
                                ? Monad[M].map(us.o) { uOpt: &Option<U> ->
 | 
						|
                                    uOpt is Some(u) ? Some(f(u)) : None
 | 
						|
                                }
 | 
						|
                                : Monad[M].lift(None)
 | 
						|
                    }
 | 
						|
            )
 | 
						|
        }
 | 
						|
 | 
						|
        fn <U> flatMap(f: fn (t: &T) -> Self[M]<U>) -> Self[M]<U> {
 | 
						|
            OptionT(
 | 
						|
                Monad[M].flatMap(o) {
 | 
						|
                    it is Some(t) ? f(t).o : Monad[M].lift(None)
 | 
						|
                }
 | 
						|
            )
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    impl Into<Self[M]<T>, M<Option<T>>> {
 | 
						|
        cons fn into() -> M<Option<T>> = o
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
pub int List<T> : Iterable<T> + Zero[Self<T>] + Monad[Self<T>] {
 | 
						|
    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<T>] {
 | 
						|
        fn <U> map(f: fn (t: &T) -> U) -> Self<U> {
 | 
						|
            let out: List<U> = Zero[Self<U>].zero()
 | 
						|
            for item in self { // item is &T
 | 
						|
                out << f(item)
 | 
						|
            }
 | 
						|
            out
 | 
						|
        }
 | 
						|
 | 
						|
        static fn lift(t: T) -> Self<T> = ArrayList(t)
 | 
						|
 | 
						|
        fn <U ,V> apply(us: &Self<U>) -> Self<V> where T : fn (u: &U) -> V {
 | 
						|
            let out: List<V> = Zero[Self<V>].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 <U> flatMap(f: fn (t: &T) -> Self<U>) -> Self<U> {
 | 
						|
            let out: List<U> = Zero[Self<U>].zero()
 | 
						|
            for t in self { // t is &T
 | 
						|
                for u in Into[Self<U>, Iterator<U>].into(f(t)) { // u is U
 | 
						|
                    out << u // out take ownership of u
 | 
						|
                }
 | 
						|
            }
 | 
						|
            out
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
pub class LinkedList<T> : List<T> {
 | 
						|
 | 
						|
    // inner classes are static by default
 | 
						|
    class Node<T>(data: T) {
 | 
						|
        mut next: Option<Self<T>>
 | 
						|
    }
 | 
						|
 | 
						|
    mut fld head: Option<Node<T>>
 | 
						|
 | 
						|
    impl mut fn add(t: T) -> Void {
 | 
						|
        match head {
 | 
						|
            None => {
 | 
						|
                head = Some(Node(t))
 | 
						|
            }
 | 
						|
            Some => {
 | 
						|
                let mut current: &Option<Node<T>> = &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<Node<T>> = &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<Node<T>> = &head
 | 
						|
        () -> {
 | 
						|
            if let Some(node) = current {
 | 
						|
                let data: &T = &node.data
 | 
						|
                current = &node.next
 | 
						|
                Some(data)
 | 
						|
            } else {
 | 
						|
                None
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    impl Into[Self<T>, Iterator<T>] {
 | 
						|
        cons fn into() -> Iterator<T> {
 | 
						|
            let mut current: Option<Node<T>> = 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<T>] {
 | 
						|
        static fn zero() -> Self<T> = LinkedList()
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
fn optionTListDemo() {
 | 
						|
    let oddsOnly: List<Option<Int>> = [
 | 
						|
        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
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |