Skip to content

Instantly share code, notes, and snippets.

@Lucifier129
Created June 30, 2018 01:27
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Lucifier129/1172cbefce49205e0391be2c69aa5921 to your computer and use it in GitHub Desktop.
Save Lucifier129/1172cbefce49205e0391be2c69aa5921 to your computer and use it in GitHub Desktop.
var noop = () => {}
var compose = (f1, f2) => (...args) => f1(f2(...args))
var range = (start, end) => {
let n = start
let f = (next, complete) => {
if (n <= end) {
next(n++)
f(next, complete)
} else {
complete()
}
}
return f
}
var map = (source, f) => (next, complete) => source(value => next(f(value)), complete)
var reverse = source => {
let f
return (next, complete) => {
let composeNext = value => {
let feedValue = () => next(value)
f = compose(
f,
feedValue
)
}
f = complete
source(composeNext, () => f())
}
}
var foreach = (source, f) => source(f, noop)
var numbers = range(1, 10)
numbers = map(numbers, function(n) {
return n * n
})
numbers = reverse(numbers)
foreach(numbers, console.log)
@Lucifier129
Copy link
Author

Lucifier129 commented Jun 30, 2018

uglify

var range = (start, end) => (next, complete) => start <= end ? range(start + 1, end)((next(start), next), complete) : complete()
var map = (source, f) => (next, complete) => source(value => next(f(value)), complete)
var reverse = source => (next, complete) => {
  let f = complete, compose = (f1, f2) => (...args) => f1(f2(...args))
  source(value => f = compose(f, () => next(value)), () => f())
}
var foreach = (source, f) => source(f, () => {})

var numbers = range(1, 10)
numbers = map(numbers, function(n) {
  return n * n
})
numbers = reverse(numbers)
foreach(numbers, console.log)

@Lucifier129
Copy link
Author

Lucifier129 commented Jul 1, 2018

haskell version

_range start end list next complete
  | start <= end = _range (start + 1) end (next start list) next complete
  | otherwise = complete list

_map f source list next complete = source list (\x xs -> next (f x) xs) complete

_reverse source list next complete = source _list _next _complete 
  where
    _list = id
    _next = \x f -> \list -> f (next x list)
    _complete = \f -> f list

toList source = source [] (\x xs -> xs ++ [x]) id
toNumber source = source 0 (\x s -> x + s) id
toString source = source "" (\n s -> s ++ show n) id

n1 = _range 1 10
n2 = _map (**2) n1
n3 = _reverse n2
list = toList n3
number = toNumber n3
string = toString n3

@Lucifier129
Copy link
Author

Lucifier129 commented Jul 2, 2018

translate haskell to javascript

var range = (start, end) => (acc, next, complete) => start <= end ? range(start + 1, end)(next(start, acc), next, complete) : complete(acc)
var map = (source, f) => (acc, next, complete) => source(acc, (item, acc) => next(f(item), acc), complete)
var reverse = source => (acc, next, complete) => source(x => x, (n, f) => acc => f(next(n, acc)), f => f(acc))
var foreach = (source, f) => source(null, n => f(n), () => {})
var numbers = range(1, 10)
numbers = map(numbers, n => n * n)
numbers = reverse(numbers)
foreach(numbers, console.log)

@CarterLi
Copy link

CarterLi commented Oct 3, 2018

function* range(start, end) { for (let i = start; i <= end; ++i) yield i }
function* map(iter, fn) { for (const x of iter) yield fn(x) }
function* reverse(iter) { for (const x of iter) yield* reverse(iter), yield x }
function foreach(iter, fn) { for (const x of iter) fn(x) }
var numbers = range(1, 10);
numbers = map(numbers, function (n) { return n * n; });
numbers = reverse(numbers);
foreach(numbers, console.log);

Ref: shiyangzhaoa/easy-tips#2

@zheeeng
Copy link

zheeeng commented Feb 20, 2019

const getHead = true
const getTail = false
const Nothing = null

const List =
  (head, tail) =>
    getHeadOrTail =>
      getHeadOrTail
        ? head
        : tail

const range =
  (start, end) =>
    List(start, start >= end ? Nothing : range(start + 1, end))

const map =
  (listIter, mapper) =>
    listIter === Nothing
      ? Nothing
      : List(mapper(listIter(getHead)), map(listIter(getTail), mapper))

const last =
  listIter =>
    listIter(getTail) === Nothing
      ? listIter(getHead)
      : last(listIter(getTail))

const initial =
  listIter =>
    listIter(getTail) === Nothing
      ? Nothing
      : List(listIter(getHead), initial(listIter(getTail)))

const reverse =
  listIter =>
    listIter(getTail) === Nothing
      ? listIter
      : List(last(listIter), reverse(initial(listIter)))

const foreach =
  (listIter, fn) =>
    listIter !== Nothing && (fn(listIter(getHead)) || foreach(listIter(getTail), fn))

foreach(reverse(map(range(1, 10), x => x * x)), console.log)

@zheeeng
Copy link

zheeeng commented Feb 20, 2019

  const GET_HEAD = 0
  const GET_TAIL = 1
  const GET_INITIAL = 2
  const GET_LAST = 3
  const MAP_OVER = 4
  const FOREACH_OVER = 5
  const REVERSE_OVER = 6
  const Nothing = null

  const List =
    (head, tail) =>
      (op, opFn) => {
        switch (op) {
          case GET_HEAD:
            return head
          case GET_TAIL:
            return tail
          case GET_INITIAL:
            return tail === Nothing ? Nothing : List(head, tail(GET_INITIAL))
          case GET_LAST:
            return tail === Nothing ? head : tail(GET_LAST)
          case MAP_OVER:
            return tail === Nothing ? List(opFn(head), Nothing) : List(opFn(head), tail(op, opFn))
          case FOREACH_OVER:
            return (opFn(head), tail !== Nothing && tail(op, opFn), undefined)
          case REVERSE_OVER:
            return tail === Nothing ? List(head, Nothing): List(tail(GET_LAST), List(head, tail)(GET_INITIAL)(op, opFn))
        }
      }

  const range =
    (start, end) =>
      List(start, start >= end ? Nothing : range(start + 1, end))

  const map = (list, mapper) => list(MAP_OVER, mapper)
  const foreach = (list, fn) => list(FOREACH_OVER, fn)
  const reverse = (list) => list(REVERSE_OVER)

  foreach(reverse(map(range(1, 10), x => x * x)), console.log)

@Lucifier129
Copy link
Author

Lucifier129 commented Feb 21, 2019

a solution via Church-encoding

// church-booleans
let True = (a, b) => a
let False = (a, b) => b

// predicate function
let predicate = (bool, f1, f2) => bool(f1, f2)()

// church-pairs
let Pair = (a, b) => f => f(a, b)
let first = pair => pair((a, b) => a)
let second = pair => pair((a, b) => b)

// church-list
let nil = Pair(True, True)
let isNil = list => first(list)
let cons = (h, t) => Pair(False, Pair(h, t))
let head = list => first(second(list))
let tail = list => second(second(list))

// list functions
let foldl = (list, f, initValue) =>
  predicate(
    isNil(list),
    () => initValue,
    () => foldl(tail(list), f, f(head(list), initValue))
  )

let map = (list, f) =>
  predicate(
    isNil(list),
    () => nil,
    () => cons(f(head(list)), map(tail(list), f))
  )

let reverse = list => foldl(list, cons, nil)

let range = (start, end) =>
  start <= end ? cons(start, range(start + 1, end)) : nil

// helper functions
let foreach = map

// testing
let numbers = range(1, 10)
numbers = map(numbers, n => n * n)
numbers = reverse(numbers)
foreach(numbers, console.log)

@Lucifier129
Copy link
Author

a solution via codata

const unit = (value) => (unit, cons) => unit(value);
const cons = (a, b) => (unit, cons) => cons(a(unit, cons), b(unit, cons));

const list = cons(unit(0), cons(unit(1), unit(2)));

const range = (start, end) => {
  if (start === end) return unit(end);
  return cons(unit(start), range(start + 1, end));
};

const map = (list, f) => (unit, cons) =>
  list(
    (value) => unit(f(value)),
    (a, b) => cons(a, b)
  );

const reverse = (list) =>
  list(
    (value) => unit(value),
    (a, b) => cons(b, a)
  );

const foreach = (list, f) => list(f, () => {});

var numbers = range(1, 10);
numbers = map(numbers, function (n) {
  return n * n;
});
numbers = reverse(numbers);
foreach(numbers, console.log);

// prettier version, use the object for interfaces, not for data

const unit = value => next => next.unit(value)
const cons = (a, b) => next => next.cons(a(next), b(next))

const list = cons(unit(0), cons(unit(1), unit(2)))

const range = (start, end) => {
  if (start === end) return unit(end)
  return cons(unit(start), range(start + 1, end))
}

const map = (list, f) => next => list({
  unit: value => next.unit(f(value)),
  cons: (a, b) => next.cons(a, b)
})

const reverse = (list) => list({
  unit: value => unit(value),
  cons: (a, b) => cons(b, a)
})

const foreach = (list, f) => list({
  unit: f,
  cons: () => {}
})

var numbers = range(1, 10);
numbers = map(numbers, function (n) { return n * n });
numbers = reverse(numbers);
foreach(numbers, console.log);

@Lucifier129
Copy link
Author

codata in typescript

interface ListVisitor<T, TT> {
  unit: (value: T) => TT;
  cons: (a: TT, b: TT) => TT;
}

interface List<T> {
  <TT>(visitor: ListVisitor<T, TT>): TT;
}

const unit = <T>(value: T): List<T> => {
  return (visitor) => visitor.unit(value);
};

const cons = <T>(left: List<T>, right: List<T>): List<T> => {
  return (visitor) => {
    return visitor.cons(left(visitor), right(visitor));
  };
};

const range = (start: number, end: number): List<number> => {
  if (start === end) return unit(end);
  return cons(unit(start), range(start + 1, end));
};

interface MapFunction<T, TT> {
  (a: T): TT;
}

const map = <T, TT>(f: MapFunction<T, TT>) => (list: List<T>): List<TT> => {
  return (visitor) => {
    return list({
      unit: (value) => visitor.unit(f(value)),
      cons: (a, b) => visitor.cons(a, b),
    });
  };
};

const reverse = <T>(list: List<T>): List<T> => {
  return list({
    unit: (value) => unit(value),
    cons: (a, b) => cons(b, a),
  });
};

const foreach = <T>(f: (a: T) => any) => (list: List<T>) => {
  list({
    unit: f,
    cons: () => {},
  });
};

interface UnaryFunction<T, TT> {
  (arg: T): TT;
}

function pipe<T, A>(a: T, f1: UnaryFunction<T, A>): UnaryFunction<T, A>;
function pipe<T, A, B>(
  a: T,
  f1: UnaryFunction<T, A>,
  f2: UnaryFunction<A, B>
): UnaryFunction<T, B>;
function pipe<T, A, B, C>(
  a: T,
  f1: UnaryFunction<T, A>,
  f2: UnaryFunction<A, B>,
  f3: UnaryFunction<B, C>
): UnaryFunction<T, C>;
function pipe<T, A, B, C>(
  a: T,
  f1: UnaryFunction<T, A>,
  f2: UnaryFunction<A, B>,
  f3: UnaryFunction<B, C>
): UnaryFunction<T, C>;
function pipe<T, A, B, C, D>(
  a: T,
  f1: UnaryFunction<T, A>,
  f2: UnaryFunction<A, B>,
  f3: UnaryFunction<B, C>,
  f4: UnaryFunction<C, D>
): UnaryFunction<T, D>;

function pipe(a: any, ...args: UnaryFunction<any, any>[]) {
  return args.reduce((a, f) => f(a), a);
}

pipe(
  range(1, 10),
  map((n) => n * n),
  reverse,
  foreach(console.log)
);

/* output:

   100
   81
   64
   49
   36
   25
   16
   9
   4
   1
*/

@fc01
Copy link

fc01 commented Aug 5, 2021

type List = (i: number) => number

const range = (a: number, b: number): List =>
    i => i === -6666 ? b - a + 1 : a + i

const map = (list: List, f: (n: number) => number): List =>
    i => i === -6666 ? list(-6666) : f(list(i))

const reverse = (list: List): List =>
    i => i === -6666 ? list(-6666) : list(list(-6666) - 1 - i)


const foreach = (list: List, f: (n: number) => void) => {
    for (let i = 0; i < list(-6666); i++)f(list(i))
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment