A crucial bit of Haskell magic is that constants are polymorphic: the type of an integer constant is Num a => a. In expressions like xs+1, the constant takes on whatever type is needed to make both operands have the same type. This is done by implicitly invoking the standard function
fromInteger :: Num a => Integer -> awhich converts integers to other types. fromInteger belongs to type class Num, along with arithmetic operations + - *. The definition for converting to power series is
fromInteger c = series(fromInteger c) -- promote constantsHere fromInteger::Num a=>Integer->[a] on the left is defined in terms of fromInteger::Num a=>Integer->a on the right, which indicates that constant c must be coerced to the required type of list element before series is applied to make a list. This definition occurs as part of an instance declaration that places lists of numeric values in class Num; see the bare-bones package.
Note. The previous formula can be stated in "pointless" form:
fromInteger = series . fromInteger
F(x) = f + xF'(x)
G(x) = g + xG'(x)
then their product is given by
fg + xF'(g + xG') + xfG'
which translates straightforwardly to
(f:ft) * gs@(g:gt) = f*g : ft*gs + series(f)*gtBecause the signature of (*) is Num a=>a−>a−>a, we cannot use it for mixed-type multiplication; hence the coercion with series. When finite series are admitted, as in the practical package, fG' may be realized as [f]*gt.
Note. A more efficient, less elegant, realization of fG' is map (f*) gt.
F = f+xF' = QG = (q+xQ')(g+xG')
from which we see that f = qg and F' = (q+xQ')G' + Q'g = QG' + Q'g, and finally that
Q = q+xQ' = f /g + x(1/g)(F' − QG')
Long division in a nutshell!
f + (g+xG')F'(G)
The first term of F(G) is f+gF'(g), which is an infinite sum unless F is a finite series (i.e. a polynomial). Thus for safety we require g=0. The composition formula becomes
F(G(x)) = f + xG'F'(G)
f + (r+xR')(F'(R)) = x
For the composition F'(R) to work, we must have r=0,
which implies that f=0.
Solving for R' gives
R' = 1/F'(R)
int fs = 0 : zipWith (/) fs [1..] diff (_:ft) = zipWith (*) ft [1..]is pretty, but not ideal, for it imjects class Enum into the type contexts:
int :: (Fractional a, Enum a) => [a] -> [a] diff :: (Num a, Enum a) => [a] -> [a]Enum in the type reminds us that these operations combine coefficients with term indexes, which happen to have been described by enumeration. The reminder is heavy-handed: int pascal becomes a type error because the coefficents in pascal are power series. This could be fixed by throwing power series into class Enum (as Haskell does with rationals) or by eliminating enumerations from the program. The practical package takes the latter, gentler, alternative.
tans = revert(int(1/(1:0:1)))reveals that (1:0:1) must be a list. As the right operand of (:) is a list, the final 1 must be a list, so it gets coerced to a series.
Note. This definition is clever, but tans = sins/coss is simpler and faster.
The [0] in
pascal = 1/(1 - [[0],[1,1]])arises because (1+x)z represented as a power series in z is 0z0 + (1+x)z1. The [0] could be simplified to [].