」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > TypeScript 中的函數式編程

TypeScript 中的函數式編程

發佈於2024-11-01
瀏覽:839

Functional Programming in TypeScript

Contents

  1. Introduction
  2. TypeScript Environment
  3. Representing Data Through Functions
    1. Sets
    2. Binary Operations
    3. Go Further
  4. Euclidean Plane
    1. Drawing a Disk
    2. Drawing Horizontal and Vertical Half-planes
    3. Functions
    4. Go Further
  5. Fractals
    1. Complex Numbers and Drawing
    2. Mandelbrot Fractal
    3. Go Further

You can find source code here: https://github.com/aelassas/functional-ts

Introduction

In TypeScript, functions are nothing but objects. Hence, functions can be constructed, passed as parameter, returned from functions or assigned into variables. Thus, TypeScript has first-class functions. More precisely, TypeScript supports the following:

  • Higher-order functions arguments
  • Higher-order functions results
  • Nested functions
  • Anonymous functions
  • Closures
  • Partial application (ECMAScript 5)

This article will not discuss the basics of functional programming, as you can find numerous resources on this topic on the Internet. Instead, it will talk about functional programming in TypeScript applied to algebra, numbers, the Euclidean plane, and fractals. The examples provided in this article will start from simple to more complex but always illustrated in a simple, straightforward and easy-to-understand manner.

TypeScript Environment

To run the source code, you'll need to install Node.js. Once Node.js is installed, download the source code archive, unzip it, go to the source code folder you unzipped on a terminal, set up TypeScript environment and install all necessary dependencies with the following command:

npm install

To run numbers' demo, run the following command:

npm run numbers

To run Euclidean plane's demo, run the following command:

npm run plane

To run fractals' demo, run the following command:

npm run fractals

Representing Data Through Functions

Let S be any set of elements a, b, c ... (for instance, the books on the table or the points of the Euclidean plane) and let S' be any subset of these elements (for instance, the green books on the table or the points in the circle of radius 1 centered at the origin of the Euclidean plane).

The Characteristic Function S'(x) of the set S' is a function which associates either true or false with each element x of S.

S'(x) = true if x is in S'
S'(x) = false if x is not in S'

Let S be the set of books on the table and let S' be the set of green books on the table. Let a and b be two green books, and let c and d be two red books on the table. Then:

S'(a) = S'(b) = true
S'(c) = S'(d) = false

Let S be the set of the points in the Euclidean plane and let S' be the set of the points in the circle of radius 1 centered at the origin of the Euclidean plane (0, 0) (unit circle). Let a and b be two points in the unit circle, and let c and d be two points in a circle of radius 2 centered at the origin of the Euclidean plane. Then:

S'(a) = S'(b) = true
S'(c) = S'(d) = false

Thus, any set S' can always be represented by its Characteristic Function. A function that takes as argument an element and returns true if this element is in S', false otherwise. In other words, a set (abstract data type) can be represented through a function in TypeScript.

type Set = (x: T) => boolean

In the next sections, we will see how to represent some fundamental sets in the algebra of sets through TypeScript in a functional way, then we will define generic binary operations on sets. We will then apply these operations on numbers then on subsets of the Euclidean plane. Sets are abstract data structures, the subsets of numbers and the subsets of the Euclidean plane are the representation of abstract data-structures, and finally the binary operations are the generic logics that works on any representation of the abstract data structures.

Sets

This section introduces the representation of some fundamental sets in the algebra of sets through TypeScript.

Empty set

Functional Programming in TypeScript

Let E be the empty set and Empty its Characteristic function. In algebra of sets, E is the unique set having no elements. Therefore, Empty can be defined as follows:

Empty(x) = false if x is in E
Empty(x) = false if x is not in E

Thus, the representation of E in TypeScript can be defined as follows:

const empty = () => (e: T) => false

In algebra of sets, Empty is represented as follows:

Functional Programming in TypeScript

Thus, running the code below:

console.log('\nEmpty set:')
console.log('Is 7 in {}?', common.empty()(7))

gives the following results:

Functional Programming in TypeScript

Set All

Functional Programming in TypeScript

Let S be a set and S' be the subset of S that contains all the elements and All its Characteristic function. In algebra of sets, S' is the full set that contains all the elements. Therefore, All can be defined like this:

All(x) = true if x is in S

Thus, the representation of S' in TypeScript can be defined as follows:

const all = () => (e: T) => true

In algebra of sets, All is represented as follows:

Functional Programming in TypeScript

Thus, running the code below:

console.log('\nSet All:')
console.log('Is 7 in integers set?', common.all()(7))

gives the following results:

Functional Programming in TypeScript

Singleton Set

Let E be the Singleton set and Singleton its Characteristic function. In algebra of sets, E also known as unit set, or 1-tuple is a set with exactly one element e. Therefore, Singleton can be defined as follows:

Singleton(x) = true if x is e
Singleton(x) = false if x is not e

Thus, the representation of E in TypeScript can be defined as follows:

const singleton = (x: T) => (y: T) => x === y

Thus, running the code below:

console.log('\nSingleton set:')
console.log('Is 7 in the singleton set {0}?', common.singleton(0)(7))
console.log('Is 7 in the singleton set {7}?', common.singleton(7)(7)

gives the following results:

Functional Programming in TypeScript

Other Sets

This section presents subsets of the integers set.

Even Numbers

Let E be the set of even numbers and Even its Characteristic function. In mathematics, an even number is a number which is a multiple of two. Therefore, Even can be defined as follows:

Even(x) = true if x is a multiple of 2
Even(x) = false if x is not a multiple of 2

Thus, the representation of E in TypeScript can be defined as follows:

const even = (x: number) => x % 2 === 0

Thus, running the code below:

console.log('\nEven numbers set:')
console.log('Is 99 in even numbers set?', numbers.even(99))
console.log('Is 998 in even numbers set?', numbers.even(998))

gives the following results:

Functional Programming in TypeScript

Odd Numbers

Let E be the set of odd numbers and Odd its Characteristic function. In mathematics, an odd number is a number which is not a multiple of two. Therefore, Odd can be defined as follows:

Odd(x) = true if x is not a multiple of 2
Odd(x) = false if x is a multiple of 2

Thus, the representation of E in TypeScript can be defined as follows:

const odd = (x: number) => x % 2 === 1

Thus, running the code below:

console.log('\nOdd numbers set:')
console.log('Is 99 in odd numbers set?', numbers.odd(99))
console.log('Is 998 in odd numbers set?', numbers.odd(998))

gives the following results:

Functional Programming in TypeScript

Multiples of 3

Let E be the set of multiples of 3 and MultipleOfThree its Characteristic function. In mathematics, a multiple of 3 is a number divisible by 3. Therefore, MultipleOfThree can be defined as follows:

MultipleOfThree(x) = true if x is divisible by 3
MultipleOfThree(x) = false if x is not divisible by 3

Thus, the representation of E in TypeScript can be defined as follows:

const multipleOfThree = (x: number) => x % 3 === 0

Thus, running the code below:

console.log('\nMultiples of 3 set:')
console.log('Is 99 in multiples of 3 set?', numbers.multipleOfThree(99))
console.log('Is 998 in multiples of 3 set?', numbers.multipleOfThree(998))

gives the following results:

Functional Programming in TypeScript

Multiples of 5

Let E be the set of multiples of 5 and MultipleOfFive its Characteristic function. In mathematics, a multiple of 5 is a number divisible by 5. Therefore, MultipleOfFive can be defined as follows:

MultipleOfFive(x) = true if x is divisible by 5
MultipleOfFive(x) = false if x is not divisible by 5

Thus, the representation of E in TypeScript can be defined as follows:

const multipleOfFive = (x: number) => x % 5 === 0

Thus, running the code below:

console.log('\nMultiples of 5 set:')
console.log('Is 15 in multiples of 5 set?', numbers.multipleOfFive(15))
console.log('Is 998 in multiples of 5 set?', numbers.multipleOfFive(998))

gives the following results:

Functional Programming in TypeScript

Prime Numbers

A long time ago, when I was playing with Project Euler problems, I had to resolve the following one:

By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, 
we can see that the 6th prime is 13.
What is the 10 001st prime number?

To resolve this problem, I first had to write a fast algorithm that checks whether a given number is prime or not. Once the algorithm written, I wrote an iterative algorithm that iterates through primes until the 10 001st prime number was found.

Let E be the set of primes and Prime its Characteristic function. In mathematics, a prime is a natural number greater than 1 that has no positive divisors other than 1 and itself. Therefore, Prime can be defined as follows:

Prime(x) = true if x is prime
Prime(x) = false if x is not prime

Thus, the representation of E in TypeScript can be defined as follows:

const prime = (x: number) => {
  if (x 

Thus, running the code below to resolve our problem:

console.log('\nPrimes set:')
console.log('Is 2 in primes set?', numbers.prime(2))
console.log('Is 4 in primes set?', numbers.prime(4))
console.log('The 10 001st prime number is', numbers.getPrime(10001))

where getPrime is defined below:

const getPrime = (p: number) => {
  for (let i = 1, count = 0; ; i  ) {
    if (prime(i)) count  
    if (count === p) return i
  }
}

gives the following results:

Functional Programming in TypeScript

Binary Operations

This section presents several fundamental operations for constructing new sets from given sets and for manipulating sets. Below the Ven diagram in the algebra of sets.

Functional Programming in TypeScript

Union

Functional Programming in TypeScript

Let E and F be two sets. The union of E and F, denoted by E U F is the set of all elements which are members of either E and F.

Let Union be the union operation. Thus, the Union operation can be implemented as follows in TypeScript:

const union = (e: Set, f: Set) => (x: T) => e(x) || f(x)

Running the code below:

console.log('\nUnion:')
console.log('Is 7 in the union of Even and Odd Integers Set?', core.union(numbers.even, numbers.odd)(7))

gives the following results:

Functional Programming in TypeScript

Intersection

Functional Programming in TypeScript

Let E and F be two sets. The intersection of E and F, denoted by E n F is the set of all elements which are members of both E and F.

Let Intersection be the intersection operation. Thus, the Intersection operation can be implemented as follows in TypeScript:

const intersection = (e: Set, f: Set) => (x: T) => e(x) && f(x)

Running the code below:

console.log('\nIntersection:')
const multiplesOfThreeAndFive = core.intersection(numbers.multipleOfThree, numbers.multipleOfFive)
console.log('Is 15 a multiple of 3 and 5?', multiplesOfThreeAndFive(15))
console.log('Is 10 a multiple of 3 and 5?', multiplesOfThreeAndFive(10))

gives the following results:

Functional Programming in TypeScript

Cartesian Product

Functional Programming in TypeScript

Let E and F be two sets. The cartesian product of E and F, denoted by E × F is the set of all ordered pairs (e, f) such that e is a member of E and f is a member of F.

Let CartesianProduct be the cartesian product operation. Thus, the CartesianProduct operation can be implemented as follows in TypeScript:

const cartesianProduct = (e: Set, f: Set) => (x: T1, y: T2) => e(x) && f(y)

Running the code below:

console.log('\nCartesian Product:')
const cp = core.cartesianProduct(numbers.multipleOfThree, numbers.multipleOfFive)
console.log('Is (9, 15) in MultipleOfThree x MultipleOfFive? ', cp(9, 15))

gives the following results:

Functional Programming in TypeScript

Complements

Functional Programming in TypeScript

Let E and F be two sets. The relative complement of F in E, denoted by E \ F is the set of all elements which are members of E but not members of F.

Let Complement be the relative complement operation. Thus, the Complement operation can be implemented as follows in TypeScript:

const complement = (e: Set, f: Set) => (x: T) => e(x) && !f(x)
Running the code below:
console.log('\nComplement:')
const c = core.complement(numbers.multipleOfThree, numbers.multipleOfFive)
console.log('Is 15 in MultipleOfThree \\ MultipleOfFive set? ', c(15))
console.log('Is 9 in MultipleOfThree \\ MultipleOfFive set? ', c(9))

gives the following results:

Functional Programming in TypeScript

Symmetric Difference

Functional Programming in TypeScript

Let E and F be two sets. The symmetric difference of E and F, denoted by E Δ F is the set of all elements which are members of either E and F but not in the intersection of E and F.

Let SymmetricDifference be the symmetric difference operation. Thus, the SymmetricDifference operation can be implemented in two ways in TypeScript. A trivial way is to use the union and complement operations as follows:

const symmetricDifferenceWithoutXor = (e: Set, f: Set) => 
      (x: T) => union(complement(e, f), complement(f, e))(x)

Another way is to use the XOR binary operation as follows:

const symmetricDifferenceWithXor = (e: Set, f: Set) => (x: T) => e(x) !== f(x)

Running the code below:

console.log('\nSymmetricDifference without XOR:')
const sdWithoutXor = core.symmetricDifferenceWithoutXor(numbers.prime, numbers.even)
console.log('Is 2 in the symetric difference of prime and even Sets? ', sdWithoutXor(2))
console.log('Is 4 in the symetric difference of prime and even Sets? ', sdWithoutXor(4))
console.log('Is 7 in the symetric difference of prime and even Sets? ', sdWithoutXor(7))

console.log('\nSymmetricDifference with XOR:')
const sdWithXor = core.symmetricDifferenceWithXor(numbers.prime, numbers.even)
console.log('Is 2 in the symetric difference of prime and even Sets? ', sdWithXor(2))
console.log('Is 4 in the symetric difference of prime and even Sets? ', sdWithXor(4))
console.log('Is 7 in the symetric difference of prime and even Sets? ', sdWithXor(7))

gives the following results:

Functional Programming in TypeScript

Other Operations

This section presents other useful binary operations on sets.

Contains

Let Contains be the operation that checks whether or not an element is in a set. This operation is a function that takes as parameter an element and returns true if the element is in the set, false otherwise.

Thus, this operation is defined as follows in TypeScript:

const contains = (e: Set, x: T) => e(x)

Therefore, running the code below:

console.log('\nContains:')
console.log('Is 7 in the singleton {0}? ', core.contains(common.singleton(0), 7))
console.log('Is 7 in the singleton {7}? ', core.contains(common.singleton(7), 7))

gives the following result:

Functional Programming in TypeScript

Add

Let Add be the operation that adds an element to a set. This operation is a function that takes as parameter an element and adds it to the set.

Thus, this operation is defined as follows in TypeScript:

const add = (e: Set, y: T) => (x: T) => x === y || e(x)

Therefore, running the code below:

console.log('\nAdd:')
console.log('Is 7 in {0, 7}? ', core.add(common.singleton(0), 7)(7))
console.log('Is 0 in {1, 0}? ', core.add(common.singleton(1), 0)(0))
console.log('Is 7 in {19, 0}? ', core.add(common.singleton(19), 0)(7))

gives the following result:

Functional Programming in TypeScript

Remove

Let Remove be the operation that removes an element from a set. This operations is a function that takes as parameter an element and removes it from the set.

Thus, this operation is defined as follows in TypeScript:

const remove = (e: Set, y: T) => (x: T) => x !== y && e(x)

Therefore, running the code below:

console.log('\nRemove:')
console.log('Is 7 in {}? ', core.remove(common.singleton(0), 0)(7))
console.log('Is 0 in {}? ', core.remove(common.singleton(7), 7)(0))

gives the following result:

Functional Programming in TypeScript

For Those Who Want To Go Further

You can see how easy we can do some algebra of sets in TypeScript through Functional Programming. In the previous sections was shown the most fundamental definitions. But, If you want to go further, you can think about:

  • Relations over sets
  • Abstract algebra, such as monoids, groups, fields, rings, K-vectorial spaces and so on
  • Inclusion-exclusion principle
  • Russell's paradox
  • Cantor's paradox
  • Dual vector space
  • Theorems and Corollaries

Euclidean Plane

In the previous section, the fundamental concepts on sets were implemented in TypeScript. In this section, we will practice the concepts implemented on the Euclidean plane.

Drawing a Disk

Functional Programming in TypeScript

A disk is a subset of a plane bounded by a circle. There are two types of disks. Closed disks which are disks that contain the points of the circle that constitutes its boundary, and Open disks which are disks that do not contain the points of the circle that constitutes its boundary.

In this section, we will set up the Characterstic function of the Closed disk and draw it in a HTML5 page.

To set up the Characterstic function, we first need a function that calculates the Euclidean Distance between two points in the plane. This function is implemented as follows:

function distance(p1: Point, p2: Point) {
    return Math.sqrt((p1.x - p2.x) ** 2   (p1.y - p2.y) ** 2)
}

where Point is defined below:

class Point {
    x: number
    y: number

    constructor(x: number, y: number) {
        this.x = x
        this.y = y
    }
}

This formula is based on Pythagoras' Theorem.

Functional Programming in TypeScript

where c is the Euclidean distance, a² is (p1.X - p2.X)² and b² is (p1.Y - p2.Y)².

Let Disk be the Characteristic function of a closed disk. In algebra of sets, the definition of a closed disk in the reals set is as follows:

Functional Programming in TypeScript

where a and b are the coordinates of the center and R the radius.

Thus, the implementation of Disk in TypeScript is as follows:

const disk = (center: Point, radius: number) => (p: Point) => distance(p, center) 

In order to view the set in a HTML5 page, I decided to implement a function draw that draws a set in the Euclidean plane. I chose HTML5 and thus used the canvas element for drawing.

Thus, I've built the Euclidean plane illustrated below through the method draw.

Functional Programming in TypeScript

Below the implementation of the plane.

class Plane {
  width: number
  height: number

  constructor(width: number, height: number) {
    this.width = width
    this.height = height
  }

  draw(set: PlaneSet, canvasId: string) {
    const canvas = document.getElementById(canvasId) as HTMLCanvasElement
    if (!canvas) throw new Error(`Canvas with id ${canvasId} not found`)
    canvas.width = this.width
    canvas.height = this.height
    const context = canvas.getContext('2d') as CanvasRenderingContext2D
    const semiWidth = this.width / 2
    const semiHeight = this.height / 2
    const xMin = -semiWidth
    const xMax = semiWidth
    const yMin = -semiHeight
    const yMax = semiHeight
    for (let x = 0; x 

In the draw function, a canvas having the same width and the same height as the Euclidean plane container is created. Then each point in pixels (x,y) of the canvas is replaced by a black point if it belongs to the set. xMin, xMax, yMin and yMax are the bounding values illustrated in the figure of the Euclidean plane above.

Running the code below:

euclideanPlane = new Plane(200, 200)
euclideanPlane.draw(disk(new Point(0, 0), 50), 'disk')

where disk is the id of the canvas:


gives the following result:

Functional Programming in TypeScript

Drawing Horizontal and Vertical Half-planes

Functional Programming in TypeScript

A horizontal or a vertical half-plane is either of the two subsets into which a plane divides the Euclidean space. A horizontal half-plane is either of the two subsets into which a plane divides the Euclidean space through a line perpendicular with the Y axis like in the figure above. A vertical half-plane is either of the two subsets into which a plane divides the Euclidean space through a line perpendicular with the X axis.

In this section, we will set up the Characteristic functions of the horizontal and vertical half-planes, draw them in a HTML5 page and see what we can do if we combine them with the disk subset.

Let HorizontalHalfPlane be the Characteristic function of a horizontal half-plane. The implementation of HorizontalHalfPlane in TypeScript is as follows:

const horizontalHalfPlane = (y: number, isLowerThan: boolean) => 
      (p: Point) => (isLowerThan ? p.y = y)

Thus, running the code below:

euclideanPlane.draw(horizontalHalfPlane(0, true),'hhp')

where hhp is the id of the canvas:


gives the following result:

Functional Programming in TypeScript

Let VerticalHalfPlane be the Characteristic function of a vertical half-plane. The implementation of VerticalHalfPlane in TypeScript is as follows:

const verticalHalfPlane = (x: number, isLowerThan: boolean) => 
      (p: Point) => (isLowerThan ? p.x = x)
Thus, running the code below:
euclideanPlane.draw(verticalHalfPlane(0, false),'vhp')

where vhd is the id of the canvas:


gives the following result:

Functional Programming in TypeScript

In the first section of the article, we set up basic binary operations on sets. Thus, by combining the intersection of a disk and a half-plane for example, we can draw the half-disk subset.

Therefore, running the sample below:

euclideanPlane.draw(set.intersection(disk(new Point(0, 0), 50), 
                    verticalHalfPlane(0, false)), 'hd')

where hd is the id of the canvas:


gives the following result:

Functional Programming in TypeScript

Functions

This section presents functions on the sets in the Euclidean plane.

Translate

Functional Programming in TypeScript

Let translatePoint be the function that translates a point in the plane. In Euclidean geometry, translatePoint is a function that moves a given point a constant distance in a specified direction. Thus the implementation in TypeScript is as follows:

const translatePoint = (deltax: number, deltay: number) => 
                       (p: Point) => new Point(p.x   deltax, p.y   deltay)

where (deltax, deltay) is the constant vector of the translation.

Let translate be the function that translates a set in the plane. This function is simply implemented as follows in TypeScript:

const translate = (e: PlaneSet, deltax: number, deltay: number) => 
                  (p: Point) => e(translatePoint(-deltax, -deltay)(p))
`translate` takes as parameters `deltax` which is the delta distance in the first Euclidean dimension and `deltay` which is the delta distance in the second Euclidean dimension. If a point _P (x, y)_ is translated in a set _S_, then its coordinates will change to _(x', y') = (x, delatx, y, deltay)_. Thus, the point _(x' - delatx, y' - deltay)_ will always belong to the set _S_. In set algebra, `translate` is called isomorph, in other words, the set of all translations forms the _translation group T_, which is isomorphic to the space itself. This explains the main logic of the function. Thus, running the code below in our HTML5 page:
let translate_timer: ReturnType
function translate_op() {
  let deltay = 0
  clearTimeout(scale_timer)
  clearTimeout(rotate_timer)
  translate_timer = setInterval(() => {
    deltay = deltay 

where ep_op is the id of the canvas:


gives the following result:

Functional Programming in TypeScript

Homothety

Functional Programming in TypeScript

Let scalePoint be the function that sends any point M to another point N such that the segment SN is on the same line as SM, but scaled by a factor λ. In algebra of sets, Scale is formulated as follows:

Functional Programming in TypeScript

Thus the implementation in TypeScript is as follows:

const scalePoint = (lambdax: number, lambday: number, deltax: number, deltay: number) 
      => (p: Point) => new Point(lambdax * p.x   deltax, lambday * p.y   deltay)

where (deltax, deltay) is the constant vector of the translation and (lambdax, lambday) is the lambda vector.

Let scale be the function that applies an homothety on a set in the plan. This function is simply implemented as follows in TypeScript:

const scale = (e: PlaneSet, lambdax: number, lambday: number, deltax: number, 
               deltay: number) => (p: Point) => e(scalePoint(1 / lambdax, 1 / lambday, 
               -deltax / lambdax, -deltay / lambday)(p))

scale takes as parameters deltax which is the delta distance in the first Euclidean dimension, deltay which is the delta distance in the second Euclidean dimension and (lambdax, lambday) which is the constant factor vector λ. If a point P (x, y) is transformed through scale in a set S, then its coordinates will change to (x', y') = (lambdax * x, delatx, lambday * y, deltay). Thus, the point ((x'- delatx)/lambdax, (y' - deltay)/lambday) will always belong to the set S, If lambda is different from the vector 0, of course. In algebra of sets, scale is called isomorph, in other words, the set of all homotheties forms the Homothety group H, which is isomorphic to the space itself \ {0}. This explains the main logic of the function.

Thus, running the code below in our HTML5 page:

let scale_timer: ReturnType
function scale_op() {
  let deltay = 0
  let lambday = 0.05
  clearTimeout(translate_timer)
  clearTimeout(rotate_timer)
  scale_timer = setInterval(() => {
    deltay = deltay 

gives the following result:

Functional Programming in TypeScript

Rotate

Functional Programming in TypeScript

Let rotatePoint be the function that rotates a point with an angle θ. In matrix algebra, rotatePoint is formulated as follows:

Functional Programming in TypeScript

where (x', y') are the co-ordinates of the point after rotation, and the formula for x' and y' is as follows:

Functional Programming in TypeScript

The demonstration of this formula is very simple. Have a look at this rotation.

Functional Programming in TypeScript

Below the demonstration:

Functional Programming in TypeScript

Thus the implementation in TypeScript is as follows:

const rotatePoint = (theta: number) => (p: Point) => new Point(p.x * Math.cos(theta) 
      - p.y * Math.sin(theta), p.x * Math.sin(theta)   p.y * Math.cos(theta))

Let rotate be the function that applies a rotation on a set in the plane with the angle θ. This function is simply implemented as follows in TypeScript.

const rotate = (e: PlaneSet, theta: number) => (p: Point) => e(rotatePoint(-theta)(p))

rotate is a function that takes as parameter theta which is the angle of the rotation. If a point P (x, y) is transformed through rotate in a set S, then its coordinates will change to (x', y') = (x * cos(theta) - y * sin(theta), x * sin(theta), y * cos(theta)). Thus, the point (x' * cos(theta), y' * sin(theta), y' * cos(theta) - x' * sin(theta)) will always belong to the set S. In algebra of sets, rotate is called isomorph, in other words, the set of all rotations forms the Rotation group R, which is isomorphic to the space itself. This explains the main logic of the function.

Thus, running the code below in our HTML5 page:

let rotate_timer: ReturnType
function rotate_op() {
  let theta = 0
  clearTimeout(translate_timer)
  clearTimeout(scale_timer)
  rotate_timer = setInterval(() => {
    euclideanPlane.draw(rotate(horizontalHalfPlane(-90, true), theta), 'ep_op')
    theta = (theta   Math.PI / 2) % (2 * Math.PI)
  }, 1000)
}

gives the following result:

Functional Programming in TypeScript

For Those Who Want to Go Further

Very simple, isn't it? For those who want to go further, you can explore these:

  • Ellipse
  • Three-dimensional Euclidean space
  • Ellipsoide
  • Paraboloid
  • Hyperboloid
  • Spherical harmonics
  • Superellipsoid
  • Haumea
  • Homoeoid
  • Focaloid

Fractals

Functional Programming in TypeScript

Fractals are sets that have a fractal dimension that usually exceeds their topological dimension and may fall between the integers. For example, the Mandelbrot set is a fractal defined by a family of complex quadratic polynomials:

Pc(z) = z^2   c

where c is a complex. The Mandelbrot fractal is defined as the set of all points c such that the above sequence does not escape to infinity. In algebra of sets, this is formulated as follows:

Functional Programming in TypeScript

Fractals (abstract data type) can always be represented as follows in TypeScript:

type Fractal = (z: Complex, c: Complex) => Complex

Complex Numbers and Drawing

In order to be able to draw fractals, I needed to manipulate Complex numbers. Thus, I created the Complex class below:

class Complex {
    x: number
    y: number
    static zero = new Complex(0, 0)

    constructor(x: number, y: number) {
        this.x = x
        this.y = y
    }

    abs() {
        return Math.sqrt(this.x * this.x   this.y * this.y)
    }

    toString() {
        return this.x   '   i * '   this.y
    }
}

function add(z1: Complex, z2: Complex) {
    return new Complex(z1.x   z2.x, z1.y   z2.y)
}

function substract(z1: Complex, z2: Complex) {
    return new Complex(z1.x - z2.x, z1.y - z2.y)
}

function multiply(z1: Complex, z2: Complex) {
    return new Complex(z1.x * z2.x - z1.y * z2.y, z1.x * z2.y   z1.y * z2.x)
}

Mandelbrot Fractal

I created a Mandelbrot Fractal (abstract data type representation) P(z) = z^2 c that is available below.

const mandelbrot = (z: Complex, c: Complex) => add(multiply(z, z), c)
In order to be able to draw _Complex_ numbers, I created a `ComplexPlane` class. Below is the implementation in TypeScript.
class ComplexPlane {
  width: number
  height: number
  real_min: number
  real_max: number
  imaginary_min: number
  imaginary_max: number
  boundary: number
  fractalIterationsPerPixel: number
  canvasId: string

  constructor(
    width: number,
    height: number,
    real_min: number,
    real_max: number,
    imaginary_min: number,
    imaginary_max: number,
    boundary: number,
    fractalIterationsPerPixel: number,
    canvasId: string,
  ) {
    this.width = width
    this.height = height
    this.real_min = real_min
    this.real_max = real_max
    this.imaginary_min = imaginary_min
    this.imaginary_max = imaginary_max
    this.boundary = boundary
    this.fractalIterationsPerPixel = fractalIterationsPerPixel
    this.canvasId = canvasId
  }

  draw(fractal: Fractal) {
    const canvas = document.getElementById(this.canvasId) as HTMLCanvasElement
    canvas.width = this.width
    canvas.height = this.height
    const context = canvas.getContext('2d') as CanvasRenderingContext2D
    context.fillStyle = 'white'
    for (let x = 0; x 

Thus, running the code below:

const complexPlane = new ComplexPlane(300, 300, -1.5, 1.5, -1.5, 1.5, 1.5, 20, 'fractal')

const mandelbrot = (z: Complex, c: Complex) => add(multiply(z, z), c)

complexPlane.pleaseWait()

setTimeout(() => complexPlane.draw(mandelbrot), 500)

where fractal is the id of the canvas:


gives the following result:

Functional Programming in TypeScript

For Those Who Want to Go Further

For those who want to go further, you can explore these:

  • Newton Fractals
  • Julia Fractals
  • Other Fractals

That's it! I hope you enjoyed reading.

版本聲明 本文轉載於:https://dev.to/aelassas/functional-programming-in-typescript-5b6f?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • 如何解決AppEngine中“無法猜測文件類型,使用application/octet-stream...”錯誤?
    如何解決AppEngine中“無法猜測文件類型,使用application/octet-stream...”錯誤?
    appEngine靜態文件mime type override ,靜態文件處理程序有時可以覆蓋正確的mime類型,在錯誤消息中導致錯誤消息:“無法猜測mimeType for for file for file for [File]。 application/application/octet...
    程式設計 發佈於2025-05-13
  • 您如何在Laravel Blade模板中定義變量?
    您如何在Laravel Blade模板中定義變量?
    在Laravel Blade模板中使用Elegance 在blade模板中如何分配變量對於存儲以後使用的數據至關重要。在使用“ {{}}”分配變量的同時,它可能並不總是最優雅的解決方案。 幸運的是,Blade通過@php Directive提供了更優雅的方法: $ old_section =...
    程式設計 發佈於2025-05-13
  • 找到最大計數時,如何解決mySQL中的“組函數\”錯誤的“無效使用”?
    找到最大計數時,如何解決mySQL中的“組函數\”錯誤的“無效使用”?
    如何在mySQL中使用mySql 檢索最大計數,您可能會遇到一個問題,您可能會在嘗試使用以下命令:理解錯誤正確找到由名稱列分組的值的最大計數,請使用以下修改後的查詢: 計數(*)為c 來自EMP1 按名稱組 c desc訂購 限制1 查詢說明 select語句提取名稱列和每個名稱...
    程式設計 發佈於2025-05-13
  • 如何使用Regex在PHP中有效地提取括號內的文本
    如何使用Regex在PHP中有效地提取括號內的文本
    php:在括號內提取文本在處理括號內的文本時,找到最有效的解決方案是必不可少的。一種方法是利用PHP的字符串操作函數,如下所示: 作為替代 $ text ='忽略除此之外的一切(text)'; preg_match('#((。 &&& [Regex使用模式來搜索特...
    程式設計 發佈於2025-05-13
  • 為什麼不````''{margin:0; }`始終刪除CSS中的最高邊距?
    為什麼不````''{margin:0; }`始終刪除CSS中的最高邊距?
    在CSS 問題:不正確的代碼: 全球範圍將所有餘量重置為零,如提供的代碼所建議的,可能會導致意外的副作用。解決特定的保證金問題是更建議的。 例如,在提供的示例中,將以下代碼添加到CSS中,將解決餘量問題: body H1 { 保證金頂:-40px; } 此方法更精確,避免了由全局保證金重置...
    程式設計 發佈於2025-05-13
  • Java為何無法創建泛型數組?
    Java為何無法創建泛型數組?
    通用陣列創建錯誤 arrayList [2]; JAVA報告了“通用數組創建”錯誤。為什麼不允許這樣做? 答案:Create an Auxiliary Class:public static ArrayList<myObject>[] a = new ArrayList<my...
    程式設計 發佈於2025-05-13
  • Java數組中元素位置查找技巧
    Java數組中元素位置查找技巧
    在Java數組中檢索元素的位置 利用Java的反射API將數組轉換為列表中,允許您使用indexof方法。 (primitives)(鏈接到Mishax的解決方案) 用於排序陣列的數組此方法此方法返回元素的索引,如果發現了元素的索引,或一個負值,指示應放置元素的插入點。
    程式設計 發佈於2025-05-13
  • 我可以將加密從McRypt遷移到OpenSSL,並使用OpenSSL遷移MCRYPT加密數據?
    我可以將加密從McRypt遷移到OpenSSL,並使用OpenSSL遷移MCRYPT加密數據?
    將我的加密庫從mcrypt升級到openssl 問題:是否可以將我的加密庫從McRypt升級到OpenSSL?如果是這樣,如何? 答案:是的,可以將您的Encryption庫從McRypt升級到OpenSSL。 可以使用openssl。 附加說明: [openssl_decrypt()函數要求...
    程式設計 發佈於2025-05-13
  • 如何干淨地刪除匿名JavaScript事件處理程序?
    如何干淨地刪除匿名JavaScript事件處理程序?
    刪除匿名事件偵聽器將匿名事件偵聽器添加到元素中會提供靈活性和簡單性,但是當要刪除它們時,可以構成挑戰,而無需替換元素本身就可以替換一個問題。 element? element.addeventlistener(event,function(){/在這里工作/},false); 要解決此問題,請考...
    程式設計 發佈於2025-05-13
  • HTML格式標籤
    HTML格式標籤
    HTML 格式化元素 **HTML Formatting is a process of formatting text for better look and feel. HTML provides us ability to format text without us...
    程式設計 發佈於2025-05-13
  • 為什麼PYTZ最初顯示出意外的時區偏移?
    為什麼PYTZ最初顯示出意外的時區偏移?
    與pytz 最初從pytz獲得特定的偏移。例如,亞洲/hong_kong最初顯示一個七個小時37分鐘的偏移: 差異源利用本地化將時區分配給日期,使用了適當的時區名稱和偏移量。但是,直接使用DateTime構造器分配時區不允許進行正確的調整。 example pytz.timezone(&#...
    程式設計 發佈於2025-05-13
  • 如何檢查對像是否具有Python中的特定屬性?
    如何檢查對像是否具有Python中的特定屬性?
    方法來確定對象屬性存在尋求一種方法來驗證對像中特定屬性的存在。考慮以下示例,其中嘗試訪問不確定屬性會引起錯誤: >>> a = someClass() >>> A.property Trackback(最近的最新電話): 文件“ ”,第1行, attributeError:SomeClass實...
    程式設計 發佈於2025-05-13
  • CSS強類型語言解析
    CSS強類型語言解析
    您可以通过其强度或弱输入的方式对编程语言进行分类的方式之一。在这里,“键入”意味着是否在编译时已知变量。一个例子是一个场景,将整数(1)添加到包含整数(“ 1”)的字符串: result = 1 "1";包含整数的字符串可能是由带有许多运动部件的复杂逻辑套件无意间生成的。它也可以是故意从单个真理...
    程式設計 發佈於2025-05-13
  • 版本5.6.5之前,使用current_timestamp與時間戳列的current_timestamp與時間戳列有什麼限制?
    版本5.6.5之前,使用current_timestamp與時間戳列的current_timestamp與時間戳列有什麼限制?
    在時間戳列上使用current_timestamp或MySQL版本中的current_timestamp或在5.6.5 此限制源於遺留實現的關注,這些限制需要對當前的_timestamp功能進行特定的實現。 創建表`foo`( `Productid` int(10)unsigned not ...
    程式設計 發佈於2025-05-13
  • 如何在Java中正確顯示“ DD/MM/YYYY HH:MM:SS.SS”格式的當前日期和時間?
    如何在Java中正確顯示“ DD/MM/YYYY HH:MM:SS.SS”格式的當前日期和時間?
    如何在“ dd/mm/yyyy hh:mm:mm:ss.ss”格式“ gormat 解決方案:的,請訪問量很大,並應為procectiquiestate的,並在整個代碼上正確格式不多: java.text.simpledateformat; 導入java.util.calendar; 導入java...
    程式設計 發佈於2025-05-13

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3