sourcelibs/Polynomials/src/Polynomials.xtlm
1⍝# Polynomials: its macro library -- p_oly<, maths notation compiled.
2⍝# Imported with the functions, under one alias: "py:" u_se< "Polynomials".
3⍝# A macro is a function from the source text written left and right of
4⍝# its call to the source that replaces the call, run before the program
5⍝# is compiled (X_eTaL MC10). Names with m: are macros; those under h: are
6⍝# private to this file.
7
8allowed ← ⎕D c̲at ".x^+-"
9
10⍝## Parsing
11
12⍝# The text without spaces.
13ʰs̲queezed ← { t → (t ≠ f̲irst " ") r̲eplicate t }
14
15⍝# The terms of a sum: a new term at each + or - after the first
16⍝# character; each keeps its sign.
17ʰt̲erms ← { t →
18 s ← (t m̲ember? "+-") ∧ (r̲ange t̲ally t) > 1
19 (1 + '+ s̲\ s) p̲artition t
20}
21
22⍝# A term's sign and the rest.
23ʰs̲ign ← { t → (f̲irst t) = f̲irst "-" ? -1.0◆ 1.0 }
24ʰb̲ody ← { t → (f̲irst t) m̲ember? "+-" ? 1 d̲rop t◆ t }
25
26⍝# Whether a term is well formed: digits and at most one point before
27⍝# x, then nothing, x, or x^ and digits.
28ʰw̲ell? ← { t →
29 b ← ʰb̲ody t
30 0 = t̲ally b ? 0 = 1
31 k ← t̲ally w̲here b = f̲irst "x"
32 k > 1 ? 0 = 1
33 k = 0 ? ʰn̲umeral? b
34 p ← f̲irst w̲here b = f̲irst "x"
35 c ← (p − 1) t̲ake b
36 e ← p d̲rop b
37 n̲ot (0 = t̲ally c) ∨ ʰn̲umeral? c ? 0 = 1
38 0 = t̲ally e ? 1 = 1 ⍝ x alone
39 n̲ot "^" m̲atch 1 t̲ake e ? 0 = 1
40 (1 < t̲ally e) ∧ '∧ r̲/ (1 d̲rop e) m̲ember? ⎕D
41}
42
43⍝# Whether a text is a number: digits with at most one point.
44ʰn̲umeral? ← { c → (0 < t̲ally c) ∧ ('∧ r̲/ c m̲ember? ⎕D c̲at ".") ∧ 1 ≥ t̲ally w̲here c = f̲irst "." }
45
46⍝# A well-formed term's power of x.
47ʰp̲ower ← { t →
48 b ← ʰb̲ody t
49 0 = t̲ally w̲here b = f̲irst "x" ? 0
50 e ← (f̲irst w̲here b = f̲irst "x") d̲rop b
51 0 = t̲ally e ? 1
52 f̲loor f̲irst n̲umbers 1 d̲rop e
53}
54
55⍝# A well-formed term's coefficient, with its sign.
56ʰc̲oefficient ← { t →
57 b ← ʰb̲ody t
58 p ← w̲here b = f̲irst "x"
59 c ← (f̲irst p c̲at 1 + t̲ally b) − 1
60 c ← c t̲ake b
61 0 = t̲ally c ? ʰs̲ign t
62 (ʰs̲ign t) × f̲irst n̲umbers c
63}
64
65⍝## The macro
66
67⍝# @ py:p_oly< "3x^2 - 2x + 1": the polynomial written in maths
68⍝# notation, compiled into its coefficients, highest power first
69⍝# (3.0 -2.0 1.0), when the program is compiled. Notation that is not a
70⍝# polynomial in x stops the compiler at it: error[bad-polynomial].
71⍝# Nothing goes on the left (@).
72ᵐp̲oly< ← { none t →
73 ({ @ → 0 })_ none ⍝ the left side takes only @ (MC22)
74 s ← ʰs̲queezed t
75 (0 = t̲ally s) ∨ n̲ot '∧ r̲/ s m̲ember? allowed ? "bad-polynomial right" ⎕R̲EJECT t c̲at " is not a polynomial in x: use digits, x, ^, + and -"
76 ts ← ʰt̲erms s
77 n̲ot '∧ r̲/ '{ ʰw̲ell? d̲isclose ⍵ } e̲ach ts ? "bad-polynomial right" ⎕R̲EJECT t c̲at " is not a polynomial in x: each term is a number, x, or x^k"
78 k ← '{ ʰp̲ower d̲isclose ⍵ } e̲ach ts
79 c ← '{ ʰc̲oefficient d̲isclose ⍵ } e̲ach ts
80 d ← 'm̲ax r̲/ k
81 f̲ormat '{ i → '+ r̲/ (k = i) r̲eplicate c } e̲ach r̲ev o̲ffsets d + 1
82}