Crafting antiOOP: A 13-Step Journey into Functional Language (Part 3)
This third blog post outlines the core features we'll be implementing in our antiOOP language.
Welcome back guys, part 3 for antiOOP. If you are new check out the previous blog.
For source code CLICK HERE
I do daily tweets and updates on my progress so follow me here: @appyzdl5
Designing the Core Language Features
In this post, we'll design the core features of our antiOOP language. We'll focus on creating a simple yet powerful functional language that demonstrates key concepts of functional programming.
1. Basic Data Types
antiOOP will support the following basic data types:
Integers
Floats
Booleans
Strings
Lists
Functions
Example:
42 # Integer
3.14 # Float
True # Boolean
"Hello" # String
[1, 2, 3] # List
2. Variables and Immutability
In antiOOP, all variables are immutable. Once a value is bound to a name, it cannot be changed. We'll use the `let` keyword for variable binding:
let x = 5
let y = x + 3
3. Functions
Functions are first-class citizens in antiOOP. We'll use the `fn` keyword to define functions:
let add = fn(a, b) { a + b }
let result = add(3, 4)
Anonymous functions (lambdas) will also be supported:
let multiply = fn(a) { fn(b) { a * b } }
let double = multiply(2)
let result = double(5) # Returns 10
4. Recursion
Since we won't have traditional loops, recursion will be our primary means of iteration:
let factorial = fn(n) {
if (n == 0) { 1 } else { n * factorial(n - 1) }
}
5. Pattern Matching
We'll implement basic pattern matching for function arguments and control flow:
let fibonacci = fn {
(0) { 0 }
(1) { 1 }
(n) { fibonacci(n - 1) + fibonacci(n - 2) }
}
6. Higher-Order Functions
antiOOP will support higher-order functions, allowing functions to take other functions as arguments and return functions:
let map = fn(f, list) {
if (isEmpty(list)) { [] }
else { [f(head(list))] ++ map(f, tail(list)) }
}
let addOne = fn(x) { x + 1 }
let result = map(addOne, [1, 2, 3]) # Returns [2, 3, 4]
7. Lazy Evaluation
Before going into how it will look let us learn what we mean by lazy evaluation. Lazy evaluation in programming is like doing homework only when the teacher asks to see it. The computer only calculates things when they're needed, saving time and resources.
We'll implement lazy evaluation for certain operations, particularly with lists:
let infiniteOnes = fn {
[1] ++ infiniteOnes()
}
let take = fn(n, list) {
if (n == 0) { [] }
else { [head(list)] ++ take(n - 1, tail(list)) }
}
let result = take(5, infiniteOnes()) # Returns [1, 1, 1, 1, 1]
8. Basic I/O
For simplicity, we'll implement basic I/O operations:
print("Hello, World!")
let name = input("Enter your name: ")
print("Hello, " ++ name)
9. Error Handling
We'll use a simple error-handling mechanism based on pattern matching:
let divide = fn(a, b) {
if (b == 0) { Error("Division by zero") }
else { Ok(a / b) }
}
let result = match divide(10, 2) {
(Ok(value)) { "Result: " ++ toString(value) }
(Error(msg)) { "Error: " ++ msg }
}
10. Modules
To organize code, we'll implement a basic module system:
# In math.aoop
export let pi = 3.14159
export let square = fn(x) { x * x }
# In main.aoop
import math
let area = math.pi * math.square(5)
Conclusion
These core features will form the foundation of our antiOOP language. In the upcoming posts, we'll implement each of these features step by step, starting with expanding our lexer and parser to handle this syntax.
Next time, we'll dive deeper into implementing the lexer to recognize these new language constructs. Stay tuned!
Part 4 out now: