Compare commits

...

26 Commits

Author SHA1 Message Date
94bba82e49 a 2025-03-23 18:18:38 +01:00
151aeb4a5d das 2025-03-21 20:57:08 +01:00
698229eb45 linkers 2025-03-21 20:56:29 +01:00
1bc1c95904 new 2025-03-21 20:55:20 +01:00
456cf0cc7e new 2025-03-21 20:54:44 +01:00
c712b0d122 links 2025-03-21 20:54:16 +01:00
bf0d91a268 answered questions 2025-03-21 18:03:31 +01:00
8754d3537a Answered questions 2025-03-21 17:50:36 +01:00
37064bc265 Writeups readme 2025-03-21 17:50:30 +01:00
d1531d45d9 formatting 2025-03-21 17:34:11 +01:00
439eca6a95 Writeups section 2025-03-21 17:33:45 +01:00
768bb71b69 Unnecessary repetition 2025-03-21 17:32:14 +01:00
baea812155 center> 2025-03-21 17:30:18 +01:00
ceb94046ab Centered table text 2025-03-21 17:27:10 +01:00
69e94d5fa4 Added links 2025-03-21 17:26:30 +01:00
775daf2271 center 2025-03-21 17:25:30 +01:00
59dc0307b3 center 2025-03-21 17:24:36 +01:00
0420a41d3d html table nicer 2025-03-21 17:23:57 +01:00
625233299a ADded sanic logo 2025-03-21 17:19:10 +01:00
321b6d4067 Updated big README 2025-03-21 17:18:25 +01:00
b5a0c48aee Cool 2025-03-21 17:13:33 +01:00
ed3e43889e monads 2025-03-21 17:09:04 +01:00
923a17f7ff session 2 2025-03-16 17:25:05 +01:00
0dd25768c8 session 2 2025-03-16 17:24:43 +01:00
c09b029e90 removed redundant 2025-03-13 19:45:14 +01:00
82296adba1 Updated main readme with ideas 2025-03-13 19:44:22 +01:00
16 changed files with 569 additions and 22 deletions

117
README.md
View File

@ -4,36 +4,109 @@
Repository which documents my journey in learning new languages. Repository which documents my journey in learning new languages.
Currently learning: Currently learning:
<style> <style>
#rust { /* center all content within cells */
filter: invert(1); table {
} width: 100%;
border-collapse: collapse;
}
th, td {
text-align: center;
}
</style> </style>
<p align="center">
<span id="rust"> <table align="center">
<img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/rust/rust-original.svg" alt="Rust" width="50" height="50"/> <tr>
</span> <th>Language</th>
<img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/haskell/haskell-original.svg" alt="Haskell" width="50" height="50"/> <th>Idea</th>
<img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/swift/swift-original.svg" alt="Swift" width="50" height="50"/> <th>Category</th>
<img src="https://dashboard.snapcraft.io/site_media/appmedia/2021/01/coq.png" alt="Coq" width="50" height="50"/> <th>Algorithmics?</th>
</p> <th>Practical?</th>
<th>Course?</th>
</tr>
<tr>
<td><a href="https://www.rust-lang.org/">
<img src="https://upload.wikimedia.org/wikipedia/commons/thumb/2/20/Rustacean-orig-noshadow.svg/220px-Rustacean-orig-noshadow.svg.png" alt="Rust" height="50"/>
</a></td>
<td>Daily drive</td>
<td>General</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><a href="https://www.swift.org/">
<img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/swift/swift-original.svg" alt="Swift" height="50"/>
</a></td>
<td>Daily drive</td>
<td>General</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><a href="https://www.haskell.org/">
<img src="https://raw.githubusercontent.com/devicons/devicon/master/icons/haskell/haskell-original.svg" alt="Haskell" height="50"/>
</a></td>
<td>Understand functional programming</td>
<td>Theory</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td><a href="https://coq.inria.fr/">
<img src="https://dashboard.snapcraft.io/site_media/appmedia/2021/01/coq.png" alt="Coq" height="50"/>
</a></td>
<td>Understand formal verification</td>
<td>Theory</td>
<td></td>
<td></td>
<td>🤷</td>
</tr>
<tr>
<td><a href="https://futhark-lang.org/">
<img src="https://hackage.haskell.org/package/futhark-0.25.28/docs/assets/ohyes.png" alt="Futhark" height="50"/>
</a></td>
<td>Understand data parallelism</td>
<td>Theory/Fun</td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
(and C++, but that is gonna happen in embedded systems, so I won't document it here) (and C++, but that is gonna happen in embedded systems, so I won't document it here)
## Idea ## Idea
I will spend about 5 hours a week learning each language. This is **NOT** a priority, but rather a side project to keep me entertained and to learn new things. I will spend about 5 hours a week learning each language. This is **NOT** a priority, but rather a side project to keep me entertained and to learn new things.
The main idea is to use these new languages to solve problems I would normally solve with Python. Also, as the file structure suggests, I will also do some algorithmic problems in these languages. The main idea is to use these new languages to solve relevant problems!
READMEs will be present in each practical folder, where I will document my thought process and the things I learned. ## Structure
```
.
├── language
│ ├── sessions -- if I am doing a course or something
│ │ ├── 13_03 -- date (dd_mm)
│ │ │ ├── notes.md
│ │ │ └── exercises/ -- if I have any
│ |-- algorithmic -- if I am doing algorithmic problems
| |-- practical -- if I decide to do something practical (usually documentation and a submodule of the main repo)
│ |-- README.md -- main README
```
A larger, more detailed README will be present in the root of each language folder, where I will document the resources I used and the things I learned. ## Writeups
Sometimes, I find some question and/or topic so interesting, that I decide to write a blog post about it.
Check out the `writeups` folder for more information.
## Books and resources > [!NOTE]
- [The rust book](https://doc.rust-lang.org/book/) > Once a writeup is finished, I will remove it from the folder and [post it here](https://confest.im).
- [Haskell Programming from first principles](http://haskellbook.com/)
- [Learn you a Haskell for great good](http://learnyouahaskell.com/)
- [Swift documentation](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/)
## End goal
Achieve a somewhat adequate level of proficiency in these languages. I don't expect to be an expert, but I want to be able to write code in these languages without having to look up every single thing.

3
futhark/readme.md Normal file
View File

@ -0,0 +1,3 @@
<p align = "center">
<img src="https://hackage.haskell.org/package/futhark-0.25.28/docs/assets/ohyes.png" alt="Futhark" width="200"/>
</p>

View File

@ -16,6 +16,7 @@ This is the larger, more general README, which will house the main takeaways/rev
- [ToC](#toc) - [ToC](#toc)
- [Books and resources](#books-and-resources) - [Books and resources](#books-and-resources)
- [13th of March - Introduction](#13th-of-march---introduction) - [13th of March - Introduction](#13th-of-march---introduction)
- [\[16th of March - Deriving types\]](#16th-of-march---deriving-types)
# Books and resources # Books and resources
- [Haskell Programming from first principles](http://haskellbook.com/) - [Haskell Programming from first principles](http://haskellbook.com/)
@ -38,3 +39,39 @@ Because it is the simplest recursive data structure. It is a recursive data stru
The tree is simply too complex. Linked lists are easy. The tree is simply too complex. Linked lists are easy.
## [16th of March - Deriving types]
> How does one do this systematically?
**Eyeball method:**
Looking at the function definition:
1. Each parameter - what is the type of each parameter?
2. Return type - what is the type of the return value?
3. If the function calls another function, look at the type of that function.
4. Replace concrete types with type variables (a, b, c, etc.)
**Formal method[^2]:**
(on paper)
1. Write down the type of each argument and subexpression.
2. Generate equations for how types relate to each other and apply transitivity (if needed).
e.g.
$$
\begin{align*}
f &:: a \to b \to c \\
g &:: c \to e \\
\implies f \circ g &:: a \to b \to e
\end{align*}
$$
3. Solve the equations for the most general type.
> Lazy and singly-linked lists, what's the relation?
A lazy list doesnt compute all elements at once; it only computes elements as you need them.
A singly-linked list is naturally great for lazy, because each element points to the next, with the next being a thunk (actual fucking term, meaning a computation that hasn't been evaluated yet[^1]).
[^1]: More generally, a thunk is a subroutine used to inject computation into another subroutine. They delay computation until it is needed. It canonically originates from the verb *think* lmao.
[^2]: [HindleyMilner type inference](https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system)

BIN
haskell/scratch/Monadic Executable file

Binary file not shown.

BIN
haskell/scratch/Monadic.hi Normal file

Binary file not shown.

View File

@ -0,0 +1,90 @@
-- We want to take a list of divisors and a number
-- We traverse the list of divisors and check if the number is divisible by the divisor
-- If the number is divisible by the return the number divided by the divisor
-- If the number is not divisible repeatedly increment the number by 1 until it is divisible by the divisor
-- If the divisor is 0, throw an error
data MyMonad a = DivByZeroError String | NotDivisible Int | Divisible a deriving (Show)
-- This is where we define fmap (i.e. map but for monads)
-- Essentially, this is where we define what happens when we apply a function to a monad
-- i.e.:
-- fmap (+1) (Divisible 3) => Divisible 4
-- fmap (+1) (NotDivisible 3) => NotDivisible 3
-- fmap (+1) (DivByZeroError "error") => DivByZeroError "error"
instance Functor MyMonad where
fmap f (DivByZeroError s) = DivByZeroError s -- Note the error
fmap f (Divisible a) = Divisible (f a) -- Apply the function f to the value a
fmap f (NotDivisible a) = NotDivisible a -- Not divisible, propagate the value forward
-- This is where we define <*> (i.e. apply but for monads) essentially applying the
-- "wrapped" function to the "wrapped" value
-- i.e.:
-- (Divisible (+1)) <*> (Divisible 3) => Divisible 4
-- (Divisible (+1)) <*> (NotDivisible 3) => NotDivisible 3
-- (Divisible (+1)) <*> (DivByZeroError "error") => DivByZeroError "error"
instance Applicative MyMonad where
(DivByZeroError s) <*> _ = DivByZeroError s -- Note the error
(Divisible a) <*> b = fmap a b -- Apply the function a to the value b
(NotDivisible a) <*> b = NotDivisible a -- Not divisible, propagate the value forward
pure = Divisible -- Wrap the value in the Divisible constructor
-- This is where we define >>=, the bind operator, which chains monadic operations
-- i.e. in this case, we chain:
-- tryDivide 2 420 >>= tryDivide 3 >>= tryDivide 5 >>= tryDivide 9 >>= tryDivide 0
-- If we encounter a DivByZeroError, we propagate it forward (i.e. we don't do anything)
-- If we encounter a NotDivisible, we propagate it forward
-- If we encounter a Divisible, we apply the function f to the value x
instance Monad MyMonad where
DivByZeroError msg >>= _ = DivByZeroError msg -- if we encounter a DivByZeroError, we propagate it forward
NotDivisible n >>= _ = NotDivisible n -- if we encounter a NotDivisible, we propagate it forward
Divisible x >>= f = f x -- if we encounter a Divisible, we apply the function f to the value x
-- Try to divide the number n by d
tryDivide :: Int -> Int -> MyMonad Int
tryDivide 0 _ = DivByZeroError "Division by zero"
tryDivide d n
| n `mod` d == 0 = Divisible (n `div` d)
| otherwise = NotDivisible n
-- Sequentially divide the number n by the divisors in the list
sequentialDividing :: [Int] -> Int -> MyMonad Int
sequentialDividing [] n = return n
sequentialDividing (d:ds) n = do
newN <- tryDivide d n -- Note how we're not doing any pattern matching here, we're just applying the function, and the monad takes care of the rest
sequentialDividing ds newN
main :: IO ()
main = do
let divisors = [2, 3, 5, 9, 0]
let number = 420
-- 420/2 = 210
-- 210/3 = 70
-- 70/5 = 14
-- 14/9 not good => 14 is returned
print $ sequentialDividing divisors number
let divisors2 = [2, 3, 5, 7, 0]
let number2 = 420
-- 420/2 = 210
-- 210/3 = 70
-- 70/5 = 14
-- 14/7 = 2
-- 2/0 not good => error
print $ sequentialDividing divisors2 number2
let divisors3 = [2, 3, 5, 7, 2]
let number3 = 420
-- 420/2 = 210
-- 210/3 = 70
-- 70/5 = 14
-- 14/7 = 2
-- 2/2 = 1, all good => 1 is returned
print $ sequentialDividing divisors3 number3
-- [Divisible 210,Divisible 140,Divisible 84,NotDivisible 420,DivByZeroError "Division by zero"]
-- 420 is divisible by: [2,3,5]
-- Wtf is the point of a monad here?

BIN
haskell/scratch/Monadic.o Normal file

Binary file not shown.

View File

@ -0,0 +1,66 @@
-- error handling with a custom monad
-- say we want to divide a list of numbers by a divisor
-- if the divisor is even, we throw an error, then apply ^2 to the rest of the numbers
-- if the divisor is odd, we return the result
-- if the divisor is 0, we throw an error
-- custom monad
data MyMonad a = DivByZeroError String | DivByEven a | DivByOdd a deriving (Show)
-- instance of Functor
instance Functor MyMonad where -- Functor is where we define fmap (i.e. map)
-- customMap, where we have 2 functions, one for even and one for odd
fmap f (DivByZeroError s) = DivByZeroError s
fmap f (DivByEven a) = DivByEven (f a)
fmap f (DivByOdd a) = DivByOdd (f a)
-- instance of Applicative
instance Applicative MyMonad where
(DivByZeroError s) <*> _ = DivByZeroError s
-- DivByEvenError -> ^2
(DivByEven a) <*> b = fmap a b --
(DivByOdd a) <*> b = fmap a b
pure = DivByOdd
-- instance of Monad
instance Monad MyMonad where
return = pure
(DivByZeroError s) >>= _ = DivByZeroError s
(DivByEven a) >>= f =
case f a of
DivByOdd b -> DivByEven b -- propagate the "evenness context" forward
DivByEven b -> DivByEven b -- keep even state if it continues
DivByZeroError s -> DivByZeroError s
(DivByOdd a) >>= f = f a
safeDivide :: Int -> [Int] -> MyMonad [Int]
safeDivide 0 _ = DivByZeroError "Division by zero"
safeDivide d xs
| even d = DivByEven (map (^2) xs)
| otherwise = DivByOdd (map (`div` d) xs)
main :: IO ()
main = do
let nums = [69, 420, 666, 1337]
let divisor = 2
let result = safeDivide divisor nums
let nums2 = [1,2,3,4,5]
let divisor2 = 0
let result2 = safeDivide divisor2 nums2
let nums3 = [69, 420, 666, 1337]
let divisor3 = 3
let result3 = safeDivide divisor3 nums3
print result
print result2
print result3

View File

@ -0,0 +1,106 @@
## Table
| Topic | Description | Confidence |
|-------|-------------|------------|
| Signatures | Checking whether the expression types are correct | 😐 |
| Programming | Writing code to solve an algorithmic problem | 😐 |
| Higher order functions | Demonstrate understanding of higher order functions, usually by chaining them | 😊 |
| List comprehensions | Demonstrate understanding of list comprehensions | 😊 |
| Recursion/infinite lists | Infinitely generating lists, usually by recursion and/or list comprehensions | 😐 |
| ADTs | Algebraic Data Types, usually defining a data type and writing functions that operate on it | 😕 |
| Proof on lists | Proving properties of functions that operate on lists | 😕 |
| Proof on trees/ADTs | Proving properties of functions that operate on trees or ADTs | 😕 |
## Deducing types systematically
### (:).(:)
```hs
expr = (:) . (:)
(:) :: a -> [a] -> [a]
(.) :: (c -> d) -> (b -> c) -> b -> d
=>
a -> ([a] -> [a]) = b -> c
b = a
c = [a] -> [a]
---
a' -> [a'] -> [a'] = c -> d
a -> [a] -> [a] = b -> c
b = a
c = [a] -> [a]
a' = [a] -> [a]
[[a] -> [a]] -> [[a] -> [a]] = d
expr :: b -> d
=>
expr :: a -> [[a] -> [a]] -> [[a] -> [a]]
```
### `f = \x y -> x (x (x y))` [^1]
```hs
f = \x y -> x (x (x y))
```
## Questions
> CLI is functional?
Not really. It fits the functional mindset.
Commands are:
- pure, input leads to output
- composable with the pipe, kinda like `(.)`
- They can be composed like higher order functions, i.e. one command can be the input to another command
In reality though, they are not functional. Their main goal is to interact with the system (a.k.a. a mutable state), which obviously breaks the functional paradigm.
> Y combinator?
A function, which allows us to define recursive functions without giving them a name. It gives us a fixed point of a function, i.e. a function that doesn't change when you apply it to itself.
In other words, finds a value $x$ such that $f(x) = x$.
```hs
y f = f (y f) -- this is the Y combinator
```
Example:
```hs
fact = \f n -> if n == 0 then 1 else n * f (n-1) -- n! = f(n) = n * f(n-1) = n * (n-1) * f(n-2) = ...
```
If we were to not use the Y combinator, we would have to define the function as:
```hs
fact = \n -> if n == 0 then 1 else n * fact (n-1)
```
> In which cases would it be impossible to not use the Y combinator?
Whenever we are working with a system that has no named functions, but we still want recursion.
In the context of Haskell, using the Y combinator (in the classical lambda calculus way) is elegant, yet not necessary.
Rewriting our factorial function using `where`:
```hs
fact :: Int -> Int
fact n = f n
where
f 0 = 1
f n = n * f (n-1)
```
is way more readable and intuitive.
## Resources
- [course](https://www.cis.upenn.edu/~cis1940/spring15/lectures.html)
- [standard list](https://hackage.haskell.org/package/base-4.21.0.0/docs/Data-List.html)
[^1]: need to find the actual rigorous way of doing this
[^2]: Referential transparency

View File

@ -0,0 +1,72 @@
// Java program to show working of user defined
// Generic classes
// We use < > to specify Parameter type
class Cat {
String breed;
String name;
boolean castrated;
Cat(String breed, String name, boolean castrated) {
this.breed = breed;
this.name = name;
this.castrated = castrated;
}
public String makeNoise() {
return "Meow";
}
}
class Test<T> {
// An object of type T is declared
T obj;
Test(T obj) {
this.obj = obj;
}
public T getObject() {
return this.obj;
}
}
class AdHocPolymorphic {
public String add(int x, int y) {
return "Sum: " + (x + y);
}
public String add(String name) {
return "Added " + name;
}
}
public class Adhoc {
public static void main(String[] args) {
AdHocPolymorphic poly = new AdHocPolymorphic();
System.out.println(poly.add(1,2)); // prints "Sum: 3"
System.out.println(poly.add("Jay")); // prints "Added Jay"
// error the fuck out
}
}
// Driver class to test above
class Main {
public static void main(String[] args) {
// instance of Integer type
Test<Integer> iObj = new Test<Integer>(15);
System.out.println(iObj.getObject());
// instance of String type
Test<String> sObj = new Test<String>("GeeksForGeeks");
System.out.println(sObj.getObject());
Test<Cat> cObj = new Test<Cat>(new Cat("Siamese", "Fluffy", true));
System.out.println(cObj.getObject().makeNoise());
}
}

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,62 @@
z :: Int -> Int
z a = 3 * a -- 3x3 = 9 => 3*3
y :: (Int -> Int) -> [Int] -> [Int]
-- y(\x -> 3*x) [1,2,3] -> [3,6,9]
y z lst = map z lst -- f(x) = 3x => f x = 3x
isEven :: Int -> Bool
isEven x = if x `mod` 2 == 0 then True else False
-- ~~mod(x, 2)~~ => x mod 2
-- isEven x = x `mod` 2 == 0
isAmongus :: String -> String
-- traverse each character and check if "amongus" is in the string, return the rest of the string
isAmongus [] = [] -- base case if the string is empty (or we reached the end of the string)
isAmongus (x : xs) -- recurse on the rest of the string
| (take 7 (x : xs) == "amongus") = drop 7 (x : xs)
| otherwise = isAmongus xs
b :: [Int] -> Int
b lst = sum (y z lst) -- = 18
allTogether :: [Int] -> Int
allTogether list = sum (map (3 *) list)
foo :: Integer -> Integer
foo 0 = 16
foo 1
| "Haskell" > "C++" = 3
| otherwise = 4
foo n
| n < 0 = 0
| n `mod` 17 == 2 = -43
| otherwise = n + 3
bogus :: [a] -> Bool
bogus (x:_) = True
bogus _ = False
main :: IO ()
main = do
print $ b [1, 2, 3]
putStrLn "AAAAAAAAA"
print $ allTogether [1, 2, 3]
putStrLn "Finding amongus"
print $ isAmongus "amongus"
print $ isAmongus "aaaaaaaaaaaaaa"
print $ isAmongus "askldhjewkjrhwekjrhwekjrhekjlfhbjerkshtjkernamogusejqwklwqhekqjwehqwjkamongusasdasdsad"
-- foos
print $ foo 0
print $ bogus [1,10..]
-- compose 2 functions with a dot
print $ (y z . y z) [1, 2, 3]
print $ (y z . y z . y z) [1, 2, 3]
print $ (.) (y z) (y z) [1, 2, 3]
print $ y z $ y z [1, 2, 3]

Binary file not shown.

View File

@ -0,0 +1,17 @@
## Lists
```hs
------------ !! mapAccumL
mapAccumL :: (s -> a -> (s, b)) -> s -> [a] -> (s, [b])
------------
```
> Generics in C?
> Implement Haskell lists in Python
> Forall and exists in functional programming
https://hackage.haskell.org/package/base-4.3.1.0/docs/src/Data-List.html

21
writeups/README.md Normal file
View File

@ -0,0 +1,21 @@
The most significant (prioritized) writeups that I'm working on can be seen in the footer at [confest.im](https://confest.im/blog), but this folder includes every "technical" (and related to the languages described here) writeup I am working on.
## Ideas and progress
Tables concerning the idea, the description and progress of the writeups I am working on.
Scale of progress:
1. 💡 - Idea stage
2. 🚧 - Structuring
3. ✏️ - Writing
4. ✅ - Finished
5. ❌ - Abandoned
---
| Idea | Description | Progress |
|------|-------------|----------|
| Memory safety | Understanding memory safety from the perspective of a Python developer | 🚧 |
---
1. The intersection of functional programming and formal verification as an amateur in both
## Miscellaneous ideas