Elliptic Fourier series are a good example to kick the tires on array programming systems; J and Python, however, are both dynamically typed.
A modern statically approach makes things significantly easier on the programmer; here I will use my Apple language, which aspires to the interactivity and conciseness of the APL family.
One has a principled yet safe version of Haskell's zip
or J's "
(re-rank on
a dyadic verb):
> :ty \f.\x.\y. f`x y
((a → (b → c)) → (Arr (i `Cons` Nil) a → (Arr (i `Cons` Nil) b → Arr (i `Cons` Nil) c)))
This avoids the pitfalls of zip
-ing different-length lists (one
cannot write eqList = zipWith (==)
in Haskell) and avoids deferring failures
to runtime as in J.
One can inspect the type signature of cons:
> :ty (<|)
(a → (Arr (i `Cons` Nil) a → Arr ((i + 1) `Cons` Nil) a))
There is a safe last
:
> :ty }.
(Arr ((i + 1) `Cons` Nil) a → a)
These work together:
> :ty \x.\xs. }.(x<|xs)
(b → (Arr (i `Cons` Nil) b → b))
I believe this combination of interactivity and type inference in array programming will be quite productive.
To address the elliptic Fourier series, we focus on the offsets \(A_0\) and \(C_0\). This is straightforward to express with mathematical notation:
\( \displaystyle A_0 = \frac{1}{T} \sum_{p=1}^{K} \left(\frac{\Delta x_p}{2\Delta t_p}(t_p^2-t_{p-1}^2) + \xi_p(t_p-t_{p-1}) \right) \\ \displaystyle C_0 = \frac{1}{T} \sum_{p=1}^{K} \left(\frac{\Delta y_p}{2\Delta t_p}(t_p^2-t_{p-1}^2) + \delta_p(t_p-t_{p-1}) \right)\)
where
\( \xi_p = \displaystyle\sum_{j=1}^{p-1}\Delta x_j - \frac{\Delta x_p}{\Delta t_p}\sum_{j=1}^{p-1}\Delta t_j \\ \delta_p = \displaystyle\sum_{j=1}^{p-1}\Delta y_j - \frac{\Delta y_p}{\Delta t_p}\sum_{j=1}^{p-1}\Delta t_j \)
In Apple:
λxs.λys.
{ sum ⇐ [(+)/1 0 x]
; dxs ⟜ (-)\~xs; dys ⟜ (-)\~ys
; dts ⟜ [√(x^2+y^2)]`dxs dys
; pxs ← (+)Λ 0 dxs; pys ← (+)Λ 0 dys; pts ⟜ (+)Λ 0 dts
; dtss ⟜ 0<|(-)\~((^2)'1 pts)
; T ⟜}.pts
; 𝜉 ← (-)`pxs ((*)`((%)`dxs dts) pts)
; 𝛿 ← (-)`pys ((*)`((%)`dys dts) pts)
; A ← ((sum ((*)`((%)`dxs dts) dtss))%2 + (sum ((*)`𝜉 dts)))%T
; C ← ((sum ((*)`((%)`dys dts) dtss))%2 + (sum ((*)`𝛿 dts)))%T
; (A,C)
}
This all typechecks! So we can be sure that there will not be off-by-one errors.