Skip to content

Instantly share code, notes, and snippets.

const always = value =>
new Parser(stream => new Success(value, stream))
const never = value =>
new Parser(stream => new Failure(value, stream))
const append = (p1, p2) =>
p1.chain(vs => p2.map(v => vs.concat([v])))
const concat = (p1, p2) =>
const either = list =>
new Parser(stream => {
for (let i = 0; i < list.length; i++) {
const parser = list[i]
const result = parser.run(stream)
if (result instanceof Success) {
return result
}
}
return new Failure('either failed', stream)
char('a')
.chain(v1 =>
char('b')
.chain(v2 =>
char('c')
.map(v3 => [v1, v2, v3])
)
)
.run('abc')
.fold(
char('a')
.chain(v => char('b'))
.chain(v => char('c'))
.run('abc')
.fold(
v => console.log('success', v)
e => console.log('error', e)
)
// => success c
char('a')
.bimap(
v => v,
e => 'character was not an a'
)
.run('b')
.fold(
v => console.log('success', v)
e => console.log('error', e)
)
char('a')
.map(v => v.toUpperCase())
.run('a')
.fold(
v => console.log('success', v)
e => console.log('error', e)
)
// => success A
char('a')
.run('a')
.fold(
v => console.log('success', v)
e => console.log('error', e)
)
// => success a
char('a')
.run('b')
const where = predicate =>
new Parser(stream => {
if (stream.length === 0) {
return new Failure('unexpected end', stream)
}
const value = stream.head()
if (predicate(value)) {
return new Success(value, stream.move(1))
}
return new Failure('predicate did not match', stream)
const char = c =>
new Parser(stream => {
if (stream.length === 0) {
return new Failure('unexpected end', stream))
}
const value = stream.head()
if (value === c) {
return new Success(value, stream.move(1))
}
return new Failure('char did not match', stream))
class Parser {
constructor(parse) {
this.parse = parse
}
run(iterable) {
if (iterable instanceof Stream) {
return this.parse(iterable)
} else {
return this.parse(new Stream(iterable))
}