# 2.45

## 练习 2.45 可以将right-split和up-split表述为某种广义划分操作的实例。请定义一个过程split，使它具有如下性质，求值：

(define right-split (split beside below))
(define up-split (split below beside))


### the Jeff Tian painter

img = document.querySelector('#jeff-tian');

const framedPainter = (frameX, frameY, frameWidth, frameHeight) => (painter) => {
painter(frameX, frameY, frameWidth, frameHeight);
};

drawToFrame = (frame, width, height) => (framedPainter) => {
const canvas = document.querySelector(frame);
canvas.width = width;
canvas.height = height;

const ctx = canvas.getContext('2d');
framedPainter(ctx);
};

const createPainter = (image, sourceX, sourceY, sourceWidth, sourceHeight) => (frameX, frameY, frameWidth, frameHeight) => (ctx) => {
ctx.drawImage(image, sourceX, sourceY, sourceWidth, sourceHeight, frameX, frameY, frameWidth, frameHeight);
};

// (x, y, w, h) -> ctx -> void
jeffTianPainter = createPainter(img, 0, 0, img.naturalWidth, img.naturalHeight);

if(img.complete) {
handler();
}

};

img.onerror = () => {
};


### beside

// ((x, y, w, h) -> ctx -> void,
// (x, y, w, h) -> ctx -> void) ->
// (x, y, w, h) -> ctx -> void
beside = (painter1, painter2) => (x, y, w, h) => (ctx) => {
ctx.save();
painter1(x, y, Math.floor(w/2), h)(ctx);
ctx.restore();
ctx.save();
painter2(x + Math.floor(w/2) + 1, y, Math.ceil(w/2), h)(ctx);
ctx.restore();
};

// (x, y, w, h) -> ctx -> void
const besidePainter = beside(jeffTianPainter, jeffTianPainter);



### below

below = (painter1, painter2) => (x, y, w, h) => (ctx) => {
ctx.save();
painter1(x, y, w, Math.floor(h/2))(ctx);
ctx.restore();
ctx.save();
painter2(x, y + Math.floor(h/2)+1, w, Math.ceil(h/2))(ctx);
ctx.restore();
};

const belowPainter = below(jeffTianPainter, jeffTianPainter);



### 向右分割

split = (op1, op2) => (painter, n) => {
if (n === 0) {
return painter;
}

const smaller = split(op1, op2)(painter, n-1);

return op1(painter, op2(smaller, smaller));
};

rightSplit = split(beside, below);

const rightSplit1 = rightSplit(jeffTianPainter, 1);



### 向上分割

upSplit = split(below, beside);

const upSplit4 = upSplit(jeffTianPainter, 4);



below = (painter1, painter2) => (x, y, w, h) => (ctx) => {
ctx.save();
painter2(x, y, w, Math.floor(h/2))(ctx);
ctx.restore();
ctx.save();
painter1(x, y + Math.floor(h/2)+1, w, Math.ceil(h/2))(ctx);
ctx.restore();
};

upSplit = split(below, beside);

const upSplit1 = upSplit(jeffTianPainter, 1);



(define (split op1 op2)
(define (op painter n)
(if (= n 0) painter
(
(define smaller ((split op1 op2) painter (- n 1)))
(op1 painter (op2 smaller smaller))
)
)

op
)