Skip to content

Commit 1b4f8c6

Browse files
committed
more fun
1 parent 6bb5639 commit 1b4f8c6

File tree

9 files changed

+300
-66
lines changed

9 files changed

+300
-66
lines changed

lambda/church/boolean.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package church
2+
3+
type Boolean = Term
4+
5+
// True If Else == \If.\Else.If
6+
func True(iF Term) Term {
7+
return func(eLse Term) Term { return iF }
8+
}
9+
10+
// False If Else == \If.\Else.Else
11+
func False(iF Term) Term {
12+
return Zero(iF)
13+
}
14+
15+
/*
16+
Simplified Syntax:
17+
A ? B : C == \A.ABC
18+
*/
19+
20+
// Not p == p ? False : True
21+
func Not(p Boolean) Boolean {
22+
return p(False)(True)
23+
}
24+
25+
// And p q == p ? q : p
26+
func And(p Boolean) Boolean {
27+
return func(q Boolean) Boolean { return p(q)(p) }
28+
}
29+
30+
// Or p q == p ? p : q
31+
func Or(p Boolean) Boolean {
32+
return func(q Boolean) Boolean { return p(p)(q) }
33+
}
34+
35+
// Xor p q == p ? not q : q
36+
func Xor(p Boolean) Boolean {
37+
return func(q Term) Term { return p(Not(q))(q) }
38+
}
39+
40+
// Pair x y p == \x.\y.\p.pxy
41+
func Pair(left Term) Term {
42+
return func(right Term) Term {
43+
return func(p Term) Term { return p(left)(right) }
44+
}
45+
}
46+
47+
// Left == \p . p True
48+
// Left (Pair x y) = x
49+
func Left(p Term) Term {
50+
return p(True)
51+
}
52+
53+
// Right == \p . p False
54+
// Right (Pair x y) = y
55+
func Right(p Term) Term {
56+
return p(False)
57+
}

lambda/church/boolean_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package church
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func evalBool(b Boolean) bool {
10+
var (
11+
value bool
12+
mark Term = func(Term) Term { value = true; return nil }
13+
unmark Term = func(Term) Term { value = false; return nil }
14+
)
15+
16+
b(mark)(unmark)(False)
17+
18+
return value
19+
}
20+
21+
func assertFalse(t *testing.T, b Boolean) {
22+
assert.False(t, evalBool(b))
23+
}
24+
25+
func assertTrue(t *testing.T, b Boolean) {
26+
assert.True(t, evalBool(b))
27+
}
28+
29+
func TestBool(t *testing.T) {
30+
assertFalse(t, False)
31+
assertTrue(t, True)
32+
}
33+
34+
func TestNot(t *testing.T) {
35+
assertFalse(t, Not(True))
36+
assertTrue(t, Not(False))
37+
}
38+
39+
func TestAnd(t *testing.T) {
40+
assertFalse(t, And2(False, False))
41+
assertFalse(t, And2(False, True))
42+
assertFalse(t, And2(True, False))
43+
assertTrue(t, And2(True, True))
44+
}
45+
46+
func TestOr(t *testing.T) {
47+
assertFalse(t, Or2(False, False))
48+
assertTrue(t, Or2(False, True))
49+
assertTrue(t, Or2(True, False))
50+
assertTrue(t, Or2(True, True))
51+
}
52+
53+
func TestXor(t *testing.T) {
54+
assertFalse(t, Xor2(False, False))
55+
assertTrue(t, Xor2(True, False))
56+
assertTrue(t, Xor2(False, True))
57+
assertFalse(t, Xor2(True, True))
58+
}
59+
60+
func TestPair(t *testing.T) {
61+
p := Pair2(True, False)
62+
assertTrue(t, Left(p))
63+
assertFalse(t, Right(p))
64+
65+
assert.Equal(t, 0, evalInt(Left(Pair2(Zero, One))))
66+
assert.Equal(t, 1, evalInt(Right(Pair2(Zero, One))))
67+
}

lambda/church/compare.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package church
2+
3+
// IsZero n == n (\x.False) True
4+
//
5+
// explanation: if n equals Zero, it will take
6+
// second argument (which is True), otherwise
7+
// it will chain (\x.False) ... (\x.False) True,
8+
// which is always equal to False
9+
func IsZero(n Numeral) Boolean {
10+
return n(func(Term) Term { return False })(True)
11+
}
12+
13+
// LessOrEqual m n == IsZero (Sub m n)
14+
func LessOrEqual(m Numeral) Term {
15+
return func(n Numeral) Boolean {
16+
return IsZero(Sub(m)(n))
17+
}
18+
}
19+
20+
// Less m n == Not (LessOrEqual n m)
21+
func Less(m Numeral) Term {
22+
return func(n Term) Term {
23+
return Not(LessOrEqual(n)(m))
24+
}
25+
}
26+
27+
// Equal m n == And (LessOrEqual m n) (LessOrEqual n m)
28+
func Equal(m Numeral) Term {
29+
return func(n Numeral) Boolean {
30+
return And(LessOrEqual(m)(n))(LessOrEqual(n)(m))
31+
}
32+
}

lambda/church/compare_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package church
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func assertBool(t *testing.T, exp bool, got Boolean) {
10+
assert.Equal(t, exp, evalBool(got))
11+
}
12+
13+
func TestCompare(t *testing.T) {
14+
// IsZero
15+
assertTrue(t, IsZero(Zero))
16+
for _, n := range nums[1:] {
17+
assertFalse(t, IsZero(n))
18+
}
19+
20+
// LessOrEqual
21+
for i, a := range nums {
22+
for j, b := range nums {
23+
assertBool(t, i <= j, LessOrEqual2(a, b))
24+
}
25+
}
26+
27+
// Less
28+
for i, a := range nums {
29+
for j, b := range nums {
30+
assertBool(t, i < j, Less2(a, b))
31+
}
32+
}
33+
34+
// Equal
35+
for i, a := range nums {
36+
for j, b := range nums {
37+
assertBool(t, i == j, Equal2(a, b))
38+
}
39+
}
40+
}

lambda/church/multiarg.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package church
2+
3+
func Add2(m, n Numeral) Numeral { return Add(m)(n) }
4+
func Mul2(m, n Numeral) Numeral { return Mul(m)(n) }
5+
func Sub2(m, n Numeral) Numeral { return Sub(m)(n) }
6+
7+
func Xor2(p, q Boolean) Boolean { return Xor(p)(q) }
8+
func And2(p, q Boolean) Boolean { return And(p)(q) }
9+
func Or2(p, q Boolean) Boolean { return Or(p)(q) }
10+
11+
func Pair2(x, y Term) Term { return Pair(x)(y) }
12+
13+
func LessOrEqual2(m, n Numeral) Boolean { return LessOrEqual(m)(n) }
14+
func Less2(m, n Numeral) Boolean { return Less(m)(n) }
15+
func Equal2(m, n Numeral) Boolean { return Equal(m)(n) }

lambda/church/numeral.go

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,61 @@
11
package church
22

3-
import . "github.com/nikmy/algo/lambda/function"
3+
// Term is lambda-abstraction
4+
type Term func(Term) Term
45

5-
func FixedPoint(f Numeral) Numeral {
6-
return f
7-
}
8-
9-
// Numeral n f x == f^n(x) = f(f(...f(x)...)...)
10-
type Numeral Lambda[Numeral, Numeral]
6+
// Numeral is such n that n f x == \f.f^n(x) = \f.f(f(...f(x)...)...)
7+
type Numeral = Term
118

129
// Zero == \f.\x.x
13-
func Zero(_ Numeral) Numeral {
14-
return func(x Numeral) Numeral { return x }
10+
func Zero(_ Term) Term {
11+
return func(x Term) Term { return x }
1512
}
1613

1714
// One == \f.\x.fx
18-
func One(f Numeral) Numeral {
19-
return func(x Numeral) Numeral { return f(x) }
15+
func One(f Term) Term {
16+
return func(x Term) Term { return f(x) }
2017
}
2118

22-
// Inc n f == f (n f)
19+
// Inc n f == \f.\n.f(nf)
2320
func Inc(n Numeral) Numeral {
24-
return func(f Numeral) Numeral {
25-
return func(x Numeral) Numeral { return f(n(f)(x)) }
21+
return func(f Term) Term {
22+
return func(x Term) Term { return f(n(f)(x)) }
2623
}
2724
}
2825

29-
// Add m n == (m Inc) n
30-
func Add(m Numeral) Numeral {
26+
// Add m n == \m.\n.m Inc n
27+
func Add(m Numeral) Term {
3128
return func(n Numeral) Numeral {
3229
return m(Inc)(n)
3330
}
3431
}
3532

36-
func Add2(m, n Numeral) Numeral {
37-
return Add(m)(n)
38-
}
39-
40-
// Mul m n == m (Add n) Zero
41-
func Mul(m Numeral) Numeral {
33+
// Mul m n == \m.\n.m (Add n) Zero
34+
func Mul(m Numeral) Term {
4235
return func(n Numeral) Numeral {
4336
return m(Add(n))(Zero)
4437
}
4538
}
4639

47-
func Mul2(m, n Numeral) Numeral {
48-
return Mul(m)(n)
40+
/*
41+
Kleene's trick:
42+
43+
Let's define incStep(N) as Nth iteration of { Pair _ n |-> Pair n (Inc n) },
44+
so it maps (Pair `0` `0`) to (Pair (`N-1` f) (`N` f)), and the left side
45+
of N(incStep)(Pair 0 0) is "decremented" N
46+
*/
47+
func incStep(p Term) Term {
48+
return Pair(Right(p))(Inc(Right(p)))
49+
}
50+
51+
// Dec == \n.Left[ n incStep (Pair Zero Zero) ]
52+
func Dec(n Numeral) Numeral {
53+
return Left(n(incStep)(Pair(Zero)(Zero)))
54+
}
55+
56+
// Sub m n == m Dec n
57+
func Sub(m Numeral) Term {
58+
return func(n Term) Numeral {
59+
return n(Dec)(m)
60+
}
4961
}

0 commit comments

Comments
 (0)