Created
June 30, 2018 01:27
-
-
Save Lucifier129/1172cbefce49205e0391be2c69aa5921 to your computer and use it in GitHub Desktop.
a solution of http://lisperator.net/blog/a-little-javascript-problem/
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
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);
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)
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)
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)
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);
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
*/
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
translate haskell to javascript