Skip to content

Instantly share code, notes, and snippets.

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))
}
class Result {
constructor(value, rest) {
this.value = value
this.rest = rest
}
}
class Success extends Result {
map(fn) {
return new Success(fn(this.value), this.rest)
class Stream {
constructor(iterable, cursor, length) {
this.iterable = iterable
this.cursor = cursor || 0
this.length = length === undefined
? iterable.length - this.cursor
: length
}
// Get the first value from the iterable.
head() {
const either = parsers => input => {
for (var i = 0; i < parsers.length; i++) {
const parser = parsers[i]
const {success, rest} = parser(input)
if (success) {
return {success, rest}
}
}
return {success: false, rest: input}
}
const string = str => sequence(str.split('').map(char))
string('abc')('abcdefg')
// => { success: true, rest: 'defg' }