From Nand To Lambda
Ryan Moore
Engineer at MX.com
Volunteer Teaching Refugees to Code
Musician!
Lover of Haskell!
InSPiRAtion
Haskell Programming
From Nand To Tetris
From First Principles
Build a Modern Computer
From First Principles
From First Principles!
- Boolean Combinatory Circuits in Haskell & HDL
- Arithmetic Combinatory Circuits in Haskell & HDL
- Arithmetic Logic Unit in Haskell & HDL
- Sequential Circuits IN Haskell & HDL
- RAM in Haskell & HDL
INstaLl Some Biz
1. Exercise & Tools Repo: https://gitlab.com/paniclater/nand-to-lambda-workshop
2. Haskell: https://www.haskell.org/platform/
3. Hardware Simulation: http://www.nand2tetris.org/software.php
Haskell
&
Hardware Description Language
Similarities?
- Function input & output
- Function Composition
- Declarative, not imperative
- Achieves side effects through types
Haskell Syntax Foundation
- Function declaration
- Let ... in
- Where
- Tuple
- Type & Data Constructors
- Pattern Matching
CHIP MyChip {
IN a, b; // can be many ins
OUT out; // can be many outs
PARTS:
//Here we connect inputs and outputs using other chips!
//Wire the inputs a & b to BuiltInChip inputs,
//assign its output to a variable
BuiltInChip(aInput=a, bInput=b, out=myVar)
//Wire in the variable myVar (output of other chip) to BuiltInChips input,
//wire its output to the output of MyChip
BuiltInChip(a=myVar, b=myVar, out=out)
}
HDL
What's Up With NAND?
| Input A | Input B | Output |
|---|---|---|
| High | High | Low |
| High | Low | High |
| Low | High | High |
| Low | Low | High |
NAND in Haskell
NOT
| Input A | Input B |
|---|---|
| High | Low |
| Low | High |
Not IN HAskell
Not in HDL
Now Implement:
- and
- or
- xor
- mux
- dmux
- not16
- and16
- or16
- mux16
- mux4Way
- dmux4Way
- or8Way
- dmux8Way
- mux4Way16
- mux8Way16
Arithmetic Combinatory circuits
| Operand | Operand | Sum | Carry |
|---|---|---|---|
| 1 | 1 | 0 | 1 |
| 1 | 0 | 1 | 0 |
| 0 | 1 | 1 | 0 |
| 0 | 0 | 0 | 0 |
Half Adder
| Operand | Operand | Operand | Sum | Carry |
|---|---|---|---|---|
| 1 | 1 | 1 | 1 | 1 |
| 1 | 1 | 0 | 0 | 1 |
| 1 | 0 | 0 | 1 | 0 |
| 0 | 0 | 0 | 0 | 0 |
Full Adder
What's A Monoid, Precious?
- Algebraic Structure
- Associative Binary Operation
- Identity Element
- Monoid a
- mappend :: a -> a -> a
- mempty :: a
Monoid OR
Monoid SUM
What About A Monoidal Nand?
Nand does not have an identity value!
What About A Semigroup Nand?
Nand is not associative!
Now Implement:
- halfAdder
- fullAdder
- add16
- increment16
Extra stars if you use monoid instances in your haskell implementation!
Arithmetic Logic Unit
single Combinatory Logic Chip For All Computation!
What About Negative Numbers?
What About Subtraction?
Two's Compliment Principle
-x = 2^n - x
where x is a positive integer
n is the total binary digits availiable
In a 5 bit binary system n is 5
2^5 - 2 = 30
"two" x would be 00010
"thirty" is 11110
11110 + 00010 = 100000
Since there are only 5 bits, we trim off the 1 and get 00000
Two's Compliment Principle
The system can code a total of 2^n signed numbers
Max and min numbers are (2^n) - 1 and -2^ (n-1)
All negative numbers begin with 1
All positive numbers begin with 0
To get (-x) from x one can leave all the trailing 0s, keep the least significant 1 intact, then flip all the remaining bits
0001
No trailing zeros, keep 1.
1
Flip the other bits
lets try with 1
1111
0110
Keep the trailing zero and the first 1.
10
Flip the other bits
lets try with 6
1010
Shortcut
Flip all the bits and add 1
0110
lets try with 6
flip bits
1001
add 1
1010
Two's Compliment Principle
We've already implemented increment by 1 gates!
We've already implemented bit flipping gates!
We've already solved negative numbers and subtraction!
ALU SPEC
Inputs:
16 bit bus x[16]
16 bit bus y[16]
Control bit zx
Control bit nx
Control bit zy
Control bit ny
Control bit f
Control bit no
ALU SPEC
Outputs:
Control bit zr
Control bit ng
16 bit bus z[16]
ALU SPEC
Rules:
- Zero x input if zx
- Negate x input if nx
- Zero y input if zy
- Negate the y input with ny
- Concatenate with Add if f
- Concatenate with And if not f
- Negate the output if no
ALU TRUTH TABLE

Implement ALU in Haskell and HDL!
Parser Combinators Turning Assembly To Machine Code
INtro To Hack ASsembly
INtro To Hack ASsembly
// Computes R0 = 2 + 3 (R0 refers to RAM[0])
@2
D=A
@3
D=D+A
@0
M=D
INtro To Hack ASsembly
/***
Predefined Symbols
A: Address Register.
D: Data Register.
M: Refers to the register in Main Memory whose address is currently stored in A.
SP: RAM address 0.
LCL: RAM address 1.
ARG: RAM address 2.
THIS: RAM address 3.
THAT: RAM address 4.
R0-R15: Addresses of 16 RAM Registers, mapped from 0 to 15.
SCREEN: Base address of the Screen Map in Main Memory, which is equal to 16384.
KBD: Keyboard Register address in Main Memory, which is equal to 24576.
**/rEgisters
A, D, M
INStructions
- A-Instruction
- Concrete Address
- Symbolic Address
- C-Instruction
- Loop
A INStructions
- Concrete Address: @1010101010101010
- Symbolic Address: @Counter, @15
If the address is concrete, store that address in the A register.
If the address is symbolic, look up the symbol's address and then store that address in the A register.
C INStructions
Destination + Computation + Jump
//Destination can be A, D, M or some combination
A
D
M
AD
ADM
//Computation with operators +,-,|,!,& and arguments A,D,M,1,0
A+D
D-M
!A
A&M
//Jump can be:
JMP
JEQ
JNE
JLT
JGE
JGT
JLE
C INStructions
Computation Is RequireD
Destination and Jump Optional
//Computation only
D + M
//Computation and Destination
D=0
//Computation and Jump
D-1;JEQ
//All Three
M=A&D;JGT Predefined Symbols
/***
Predefined Symbols
A: Address Register.
D: Data Register.
M: Refers to the register in Main Memory whose address is currently stored in A.
SP: RAM address 0.
LCL: RAM address 1.
ARG: RAM address 2.
THIS: RAM address 3.
THAT: RAM address 4.
R0-R15: Addresses of 16 RAM Registers, mapped from 0 to 15.
SCREEN: Base address of the Screen Map in Main Memory, which is equal to 16384.
KBD: Keyboard Register address in Main Memory, which is equal to 24576.
**/INtro To AppLicative And Alternative
Pure
wraps a value into an applicative
(<*>)
applies a function contained by an applicative to a value held in another
(<|>)
the (<*>) that keeps trying!
Let's Parse Some Assembly!
Resources
Stephen Diel: Parsing
http://dev.stephendiehl.com/fun/002_parsers.html
Allele Dev: Applicatives and Alternatives
https://queertypes.com/posts/59-applicatives-alternatives.html
Allele Dev: Applicatives and Alternatives
https://queertypes.com/posts/59-applicatives-alternatives.html
Haskell Programming From First Principles: Chapter 14
http://haskellbook.com/
From Nand To Lambda
By Ryan Moore
From Nand To Lambda
Slides for workshop version of my journey through learning physical computing and functional programming side by side from the course Nand2Tetris: Build A Computer from First Principles and the book Haskell Programming from Foundational Principles.
- 739