forked from drspro/metta-wam
-
Notifications
You must be signed in to change notification settings - Fork 0
/
better.hvm
123 lines (106 loc) · 3.51 KB
/
better.hvm
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
// This file contains multiplication experiments. All algorithms here use
// Scott-encoded bitstrings and simple arithmetic, no FFT, P-adics nor CA.
// Change the number to select an algorithm.
Main = (Mul A6 1234 4321)
// Results:
// A0: 43552555
// A1: 5332114
// A2: 42928102
// A3: 846518
// A4: 197726
// A5: 10459
// A6: 43919 (scales better than A5)
// Algorithms
// ----------
// Mul : Kind -> U60 -> U60 -> U60
// A0 = Multiplication by repeated repeated Inc.
// A1 = Multiplication by squared repeated Inc.
// A2 = Multiplication by repeated squared Inc.
// A3 = Multiplication by squared squared Inc.
// A4 = Long Multiplication with repeated Inc.
// A5 = Long Multiplication with squared Inc.
// A6 = Long Multiplication with add-carry.
// Mul : Kind -> U60 -> U60 -> U60
(Mul A0 a b) = (U60 (Repeat a λx(Repeat b λx(Inc x) x) Zero))
(Mul A1 a b) = (U60 (Square a λx(Repeat b λx(Inc x) x) Zero))
(Mul A2 a b) = (U60 (Repeat a λx(Square b λx(Inc x) x) Zero))
(Mul A3 a b) = (U60 (Square a λx(Square b λx(Inc x) x) Zero))
(Mul A4 a b) = (U60 (Multiplier λx(Repeat a λx(Inc x) x) (Bin b)))
(Mul A5 a b) = (U60 (Multiplier λx(Square a λx(Inc x) x) (Bin b)))
(Mul A6 a b) = (U60 (Multiplier λx((Add) (Bin a) x) (Bin b)))
// Dependencies
// ------------
// Bin : U60 -> Bin
// U60 to Bin
(Bin x) = (Bin.make 60 x)
(Bin.make 0 n) = E
(Bin.make s n) = (Bin.make.go (- s 1) (% n 2) (/ n 2))
(Bin.make.go s 0 n) = (O (Bin.make s n))
(Bin.make.go s 1 n) = (I (Bin.make s n))
// Bin to U60
(U60 x) =
let case_o = λx(+ 0 (* 2 (U60 x)))
let case_i = λx(+ 1 (* 2 (U60 x)))
let case_e = 0
(x case_o case_i case_e)
// Zero : Bin
Zero = (Bin 0)
// Neg1 : Bin
Neg1 = (Bin (- 0 1))
// Repeat : U60 -> (a -> a) -> a -> a
// Applies a function N times, sequentially.
(Repeat 0 f x) = x
(Repeat n f x) = (f (Repeat (- n 1) f x))
// Square : U60 -> (a -> a) -> a -> a
// Applies a function N times, with functional squaring. Has the same effect as
// Apply, but will compute N applications of a fusible function in log2(N) time.
(Square 0 f x) = x
(Square n f x) = (Square (/ n 2) λk(f (f k)) (Repeat (% n 2) f x))
// Scott Booleans
T = λtλf(t)
F = λtλf(f)
// Scott Bins
(O x) = λo λi λe (o x) // bit 0
(I x) = λo λi λe (i x) // bit 1
E = λo λi λe e // bitstring end
// Increments a Bin.
// Inc : Bin -> Bin
(Inc x) = λo λi λe
let case_o = i
let case_i = λx (o (Inc x))
let case_e = e
(x case_o case_i case_e)
// Add : Bin -> Bin -> Bin
// Add with carry. This was the best implementation of addition without Inc I
// could come up with, but it isn't perfect. Notice how some `λo λi λe` lambdas
// are NOT shared, and how 'a_pred' is duplicated. A perfect addition function
// should be able to share these lambdas, and avoid cloning 'a_pred'. How?
Add = λa
(a // match a
λa_pred // (O a_pred) =>
λb λo λi λe
(b // match b
λb_pred // (O b_pred) =>
(o ((Add) a_pred b_pred))
λb_pred
// (I b_pred) =>
(i ((Add) a_pred b_pred))
// E =>
e)
λa_pred // (I a_pred) =>
λb λo λi λe
(b // match b
λb_pred // (O b_pred) =>
(i ((Add) a_pred b_pred))
λb_pred // (I b_pred) =>
(o (Inc ((Add) a_pred b_pred)))
e)
// E =>
λb (b))
// Multiplier: Bin -> (Bin -> Bin) -> Bin
// Multiplier (auxiliar function)
(Multiplier adder b) = (b
λb λadder (O (Multiplier adder b))
λb λadder (adder (O (Multiplier adder b)))
λadder E
adder)