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
|
|
}
|
|
}
|
|
}
|