All the code snippets on this page are live and interactive powered by the klipse plugin.
This page contains exercises for the Partial Lenses library. Each exercise
asks you to implement an optic or transform using
Partial lenses. An acceptable solution will then make all the test( ... )
cases to log Ok. In case a test( ... ) doesn't pass it logs Error and the
(wrong) result.
Most of the exercises include hints that you can reveal by placing the pointer over them. The hints are written with a particular solution in mind, but it is often possible to solve a particular exercise in more than one way.
Suggestions for additional exercises are welcome!
L.lens to access the part field of an
object.Object.assign in the setter.L.prop shorthand, which
also supports removal.const lens = 'part'const lens = L.lens(
/* getter: */ whole => '???',
/* setter: */ (part, whole) => '???'
)
const whole = {
part: 101
}
test('get', L.get(lens, whole), 101)
test('set', L.set(lens, 42, whole), {part: 42})
test('mod', L.modify(lens, R.negate, whole), {part: -101})
test('no-mutate', whole, {part: 101})
inside.part.L.compose shorthand
notation.part is removed then so is the whole object.L.removable.const lens = '???'
const nested = {
inside: {
part: 101,
more: 'stuff'
}
}
test('get', L.get(lens, nested), 101)
test('set', L.set(lens, 42, nested), {inside: {part: 42, more: 'stuff'}})
test('mod', L.modify(lens, R.negate, nested), {
inside: {part: -101, more: 'stuff'}
})
test('rem', L.remove(lens, nested), undefined)
valOf to return a lens to access value with given key.L.find to search
for an object with the given key.L.removable.const valOf = key => '???'
const data = [{key: 'en', val: 'Title'}, {key: 'sv', val: 'Rubrik'}]
test('get', L.get(valOf('en'), data), 'Title')
test('set', L.set(valOf('en'), 'The title', data), [
{key: 'en', val: 'The title'},
{key: 'sv', val: 'Rubrik'}
])
test('rem', L.remove(valOf('en'), data), [{key: 'sv', val: 'Rubrik'}])
test('emp', L.remove(valOf('sv'), L.remove(valOf('en'), data)), [])
test('ins', L.set(valOf('fi'), 'Otsikko', data), [
{key: 'en', val: 'Title'},
{key: 'fi', val: 'Otsikko'},
{key: 'sv', val: 'Rubrik'}
])
end lens to access the end of range objects that may take one
of two different forms.
start, end / num in a
range object.L.props to limit the fields that the
lens deals with.const end = '???'
test('get_num', L.get(end, {start: 1, num: 2}), 3)
test('get_end', L.get(end, {start: 1, end: 3}), 3)
test('set_num', L.set(end, 4, {start: 1, num: 2}), {start: 1, num: 3})
test('set_end', L.set(end, 4, {start: 1, end: 3}), {start: 1, end: 4})
test('set_ext', L.set(end, 4, {start: 1, num: 2, xtra: 'field'}), {
start: 1,
num: 3,
xtra: 'field'
})
x properties of the coordinate pairs.
L.removable.const xs = '???'
const coords = [
{x: 3, y: 9},
{x: 1, y: 2},
{x: 4, y: 6},
{x: 1, y: 5},
{x: 5, y: 3}
]
test('max', L.maximum(xs, coords), 5)
test('neg', L.modify([xs, L.when(x => 3 < x)], R.negate, coords), [
{x: 3, y: 9},
{x: 1, y: 2},
{x: -4, y: 6},
{x: 1, y: 5},
{x: -5, y: 3}
])
test('rem', L.remove([xs, L.when(x => x < 3)], coords), [
{x: 3, y: 9},
{x: 4, y: 6},
{x: 5, y: 3}
])
test('emp', L.remove([xs, L.when(x => 0 < x)], coords), [])
nonObject traversal that targets all non-object or primitive
properties of arbitrarily nested objects.
const nonObjects = '???'
test('max', L.maximum(nonObjects, {a: 1, b: {c: 2, d: {e: 5}}, e: 3}), 5)
test('mod', L.modify(nonObjects, R.of, {x: {y: {z: {w: 1}}}}), {
x: {y: {z: {w: [1]}}}
})
iso.L.complement on the
booleans.L.array to complement
them.L.pick to convert object shapes.L.json to convert between JSON and
objects.const iso = '???'
test(
'inv',
L.getInverse(L.inverse(iso), '{"foo":[true,false,true]}'),
'{"bar":[false,true,false]}'
)
test('get', L.get(L.inverse(iso), '{"bar":[true]}'), '{"foo":[false]}')
trn that increments primitives under xs and decrements
under ys.L.modifyOp on the leafs.L.branch to do different things to
xs and ys.L.elems and L.values
to get to the leafs.const trn = '???'
test(
'sol',
L.transform(trn, {xs: {a: 3, b: 1, c: 4}, ys: [1, 5, 9]}),
/**/ {xs: {a: 4, b: 2, c: 5}, ys: [0, 4, 8]}
)
document.querySelector('.loading-message').className = "loading-hidden";
ga('send', 'event', 'completed', 'load', Math.round((Date.now() - startTime)/1000));
accelerate_klipse();