forked from gcanti/fp-ts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path1.ts
129 lines (103 loc) · 3.25 KB
/
1.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
//
// Code for http://www.tomharding.me/2017/03/03/fantas-eel-and-specification/
//
//
// product types
//
/*
// A coordinate in 3D space
export type Coord = {
readonly x: number
readonly y: number
readonly z: number
}
// A line between two coordinates
export type Line = {
readonly from: Coord
readonly to: Coord
}
*/
// however in order to add methods to Coord we have to change the enconding using `class`
export class Coord {
/** A coordinate in 3D space */
constructor(readonly x: number, readonly y: number, readonly z: number) {}
translate(deltaX: number, deltaY: number, deltaZ: number) {
return new Coord(this.x + deltaX, this.y + deltaY, this.x + deltaZ)
}
}
export class Line {
/** A line between two coordinates */
constructor(readonly from: Coord, readonly to: Coord) {}
}
const origin = new Coord(0, 0, 0)
export const myLine = new Line(origin, origin.translate(2, 4, 6))
//
// sum types
//
/*
// using type Foo = ...
export type Square = { readonly _tag: 'Square'; readonly topleft: Coord; readonly bottomright: Coord }
export type Circle = { readonly _tag: 'Circle'; readonly centre: Coord; readonly radius: number }
export type Shape = Square | Circle
*/
// using `class`es
export class Square {
readonly _tag: 'Square' = 'Square'
constructor(readonly topleft: Coord, readonly bottomright: Coord) {}
}
export class Circle {
readonly _tag: 'Circle' = 'Circle'
constructor(readonly centre: Coord, readonly radius: number) {}
}
export type Shape = Square | Circle
export const cata = <R>(whenSquare: (s: Square) => R, whenCircle: (c: Circle) => R) => (s: Shape): R => {
switch (s._tag) {
case 'Square':
return whenSquare(s)
case 'Circle':
return whenCircle(s)
}
}
import { Endomorphism } from '../src/function'
export const translateShape = (deltaX: number, deltaY: number, deltaZ: number): Endomorphism<Shape> =>
cata<Shape>(
s => new Square(s.topleft.translate(deltaX, deltaY, deltaZ), s.bottomright.translate(deltaX, deltaY, deltaZ)),
c => new Circle(c.centre.translate(deltaX, deltaY, deltaZ), c.radius)
)
//
// Example: linked lists
//
export type List<A> = Nil<A> | Cons<A>
export class Nil<A> {
static value: List<never> = new Nil()
private constructor() {}
// we could also define cata (here renamed to fold) as a method
fold<R>(whenNil: () => R, whenCons: (head: A, tail: List<A>) => R): R {
return whenNil()
}
map<B>(f: (a: A) => B): List<B> {
return Nil.value
}
toString() {
return 'Nil.value'
}
}
export class Cons<A> {
constructor(readonly head: A, readonly tail: List<A>) {}
fold<R>(whenNil: () => R, whenCons: (head: A, tail: List<A>) => R): R {
return whenCons(this.head, this.tail)
}
map<B>(f: (a: A) => B): List<B> {
return new Cons(f(this.head), this.tail.map(f))
}
toString() {
return `new Cons(${this.head}, ${this.tail})`
}
}
export const fromArray = <A>(xs: Array<A>): List<A> =>
xs.reduceRight((acc, a) => new Cons(a, acc), Nil.value as List<A>)
export const toArray = <A>(xs: List<A>): Array<A> => xs.fold(() => [], (head, tail) => [head, ...toArray(tail)])
console.log(toArray(fromArray([1, 2, 3]).map(x => x + 2)))
// => [3, 4, 5]
console.log(fromArray([1, 2, 3]).toString())
// => new Cons(1, new Cons(2, new Cons(3, Nil.value)))