M. Douglas McIlroy의 논문 Squinting at Power Series에 나오는 멱급수(power series) 스트림 연산들을 Go의 고루틴과 채널로 구현한 패키지입니다.
멱급수
는 유리수 계수(math/big.Rat)
논문의 핵심 장치인 demand channel을 그대로 따릅니다. 급수 하나는 요청(req)과
데이터(dat) 두 채널의 쌍이며, 소비자가 req로 신호를 보내야만 다음 계수가
계산됩니다. 이로써 수요를 앞질러 계산하는 runaway가 없는 완전한 lazy evaluation이
강제됩니다.
type PS struct {
ctx context.Context
req chan struct{}
dat chan *big.Rat
}급수 하나는 실행 중인 프로세스 네트워크의 핸들입니다. 생성기(Ones, Series, X)는
context.Context를 받고, 파생 연산은 입력 급수의 컨텍스트를 상속합니다. 컨텍스트를
cancel하면 네트워크의 모든 고루틴이 종료됩니다. cancel된 뒤 Get은 nil을,
Take는 그때까지 얻은 항만 반환합니다. 서로 다른 컨텍스트에서 만든 급수를 섞으면
안 됩니다.
ctx, cancel := context.WithCancel(context.Background())
tan := squint.Rev(squint.Integ(zero, squint.Msubst(squint.Ones(ctx), negOne, 2)))
tan.Take(20)
cancel() // 모든 고루틴 종료| 함수 | 의미 | 논문의 식 |
|---|---|---|
Add(F, G) |
||
Cmul(c, F) |
||
Xmul(F) |
|
|
Deriv(F) |
||
Integ(c, F) |
||
Mul(F, G) |
(2) | |
Subst(F, G) |
|
(3) |
Msubst(F, c, n) |
||
Exp(F) |
|
|
Recip(F) |
|
|
Rev(F) |
함수적 역원: |
(8) |
Fix(ctx, f) |
재귀 매듭: |
|
Split(F, n) |
|
Fix는 미분방정식을 스트림으로 푸는 범용 콤비네이터입니다. f의 출력이 입력을
요구하기 전에 첫 항을 내놓아야 하는데(productive), Integ가 적분 상수를 먼저
내놓으므로 적분으로 시작하면 안전합니다. Exp가 이걸로 구현되어 있고,
cmd/squint에서 sin/cos
와 Riccati 방정식
Split은 논문의 do_split 프로세스 체인 대신, 큐를 가진 단일 서버 고루틴으로
구현했습니다. 다음 항을 원천에서 가져오는 동작은 비동기로 수행하여, 자기 자신의
split을 통해 재귀적으로 정의되는 급수(Exp, Recip, Rev)에서도 교착이 생기지
않습니다.
go test ./...
go run ./cmd/squint논문의 마지막 예제 —
arctan := squint.Integ(zero, squint.Msubst(squint.Ones(ctx), negOne, 2))
tan := squint.Rev(arctan)tan(x) = rev(arctan): 0 1 0 1/3 0 2/15 0 17/315 0 62/2835 0 1382/155925