Skip to content

Instantly share code, notes, and snippets.

@zhujinxuan
Created March 14, 2019 15:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zhujinxuan/dbcb03feeef9a00a194af28ea819acd5 to your computer and use it in GitHub Desktop.
Save zhujinxuan/dbcb03feeef9a00a194af28ea819acd5 to your computer and use it in GitHub Desktop.
A Naibe Sum type for typescript
enum LR { isInL, isInR }
class InL<L> {
public readonly cc: LR = LR.isInL
public readonly value : L;
constructor(x : L) {
this.value = x;
}
}
class InR<R> {
public readonly cc: LR = LR.isInR
public readonly value : R;
constructor(x : R) {
this.value = x;
}
}
interface SumInterface<L,R> {
value : InL<L> | InR<R>;
first<L1>(f : (_:L) => L1) : Sum<L1, R>;
second<R1>(g : (_:R) => R1) : Sum<L,R1>;
}
function isRight<L,R>(v : InL<L> | InR<R>) : v is InR<R> {
return v.cc === LR.isInR
}
function isLeft<L,R>(v : InL<L> | InR<R>) : v is InL<L>{
return v.cc === LR.isInL
}
export default class Sum<L, R> implements SumInterface<L,R>{
public readonly value : InL<L> | InR<R>;
constructor(x : InL<L> | InR<R>) {
this.value = x;
}
public unsafeCast<L1, R1>() : Sum<L1, R1> {
const that : Sum<any, any> = this;
return that
}
public first<L1>(f : (_:L) => L1) : Sum<L1, R> {
const {value} = this;
if (!isLeft<L,R>(value)) {
return this.unsafeCast<L1, R>()
}
const {value: old} : InL<L> = value
const l : any = f(old)
if (l === old) {
return this.unsafeCast<L1,R>()
}
return new Sum(new InL(l))
}
public second<R1>(g : (_:R) => R1) : Sum<L, R1> {
const {value} = this;
if (!isRight<L,R>(value)) {
return this.unsafeCast<L, R1>()
}
const {value: old} : InR<R> = value
const r : any = g(old)
if (r === old) {
return this.unsafeCast<L,R1>()
}
return new Sum(new InR(r))
}
}
export function mkL<L,R>(x : L) : Sum<L,R> {
return new Sum<L,R>(new InL(x))
}
export function mkR<L,R>(x : R) : Sum<L,R> {
return new Sum<L,R>(new InR(x))
}
export function plus<L,R, L1, R1>(f : (_:L) => L1, g : (_:R) =>R1 , e : Sum<L,R>) : Sum<L1, R1>{
return e.first(f).second(g)
}
export function either<L,R,C>(f :(_:L) => C, g:(_:R) => C, e: Sum<L,R>) : C{
const {value} = e
if (isLeft<L,R>(value)) {
return f(value.value)
}
return g(value.value)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment