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();