Compare commits

..

7 commits

Author SHA1 Message Date
dependabot[bot]
540cfd1310
Merge 87c7f1f18d into 9caa25dec0 2024-11-21 18:47:57 +00:00
9caa25dec0
style: different color on hover on main page
Some checks failed
CI / build-nix (push) Has been cancelled
CI / deploy (push) Has been cancelled
2024-11-02 18:34:36 -07:00
b20e4a981d
fix: trivial mathematical error
Some checks are pending
CI / build-nix (push) Waiting to run
CI / deploy (push) Blocked by required conditions
2024-11-02 03:57:36 -07:00
7600335b4d
style: change colorscheme to rose-pine, change link style 2024-11-02 03:53:43 -07:00
4803c2d68e
feat: rebrand to conditional finality 2024-11-02 03:10:02 -07:00
394718bcd4
chore: use bash instead of sh syntax highlighting
Some checks are pending
CI / build-nix (push) Waiting to run
CI / deploy (push) Blocked by required conditions
2024-11-01 12:19:50 -07:00
c708ab504f
fix: delete mistakenly released blog post
Some checks are pending
CI / build-nix (push) Waiting to run
CI / deploy (push) Blocked by required conditions
2024-10-31 23:31:49 -07:00
11 changed files with 55 additions and 243 deletions

View file

@ -1,4 +1,4 @@
# gradient ascent - yet another developer blog
# conditional finality - yet another developer blog
This repository hosts the source code for my blog, written in Haskell and
powered by [hakyll](https://jaspervdj.be/hakyll/) and
@ -14,7 +14,7 @@ you know what you are doing.
Allow the `.envrc`:
```sh
```bash
direnv allow
```
@ -28,7 +28,7 @@ Here's how to do it locally.
First, we need to build the site. Run
```sh
```bash
hakyll-site build
# sometimes, we need to ignore the cache if things aren't working
@ -51,7 +51,7 @@ In the directory, there is a `node_modules` symlink to
`result/lib/node_modules`. If we build the `nodeDeps` package, the
`node_modules` will be made available at this path. So, run the following:
```sh
```bash
nix build .#nodeDeps
```
@ -61,7 +61,7 @@ need to re-run the above command or else node_modules will not be accessible.
Finally, run the following to generate the bundled CSS and JS files.
```
```bash
rollup -c
```

View file

@ -1,5 +1,5 @@
{
description = "gradient ascent";
description = "conditional finality";
nixConfig = {
allow-import-from-derivation = "true";

View file

@ -13,12 +13,12 @@
@layer utilities {
.external-link {
@apply dark:text-violet-500 text-indigo-600 hover:bg-indigo-200 pr-3 rounded-sm dark:hover:bg-violet-950 transition-colors duration-300 relative;
@apply underline decoration-solid decoration-2 underline-offset-2 hover:text-love-light dark:hover:text-love-dark decoration-love-light decoration-love-dark;
}
.external-link::after {
@apply absolute top-1 right-[6px] w-2 h-2 border-2 border-indigo-600 dark:border-violet-600 rounded-full translate-x-1/2 -translate-y-1/2;
content: "";
.external-link-muted {
@apply underline decoration-solid decoration-2 underline-offset-2 hover:text-love-light dark:hover:text-love-dark decoration-accent-light decoration-accent-dark;
}
.small-caps {
font-variant: all-small-caps;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View file

@ -18,7 +18,7 @@ title: "youwen wu"
<div class="rounded-md p-2">
<a
href=".$url$"
class="w-fit dark:group-hover:text-muted-dark group-hover:text-muted-light transition-colors"
class="w-fit dark:group-hover:text-iris-dark group-hover:text-iris-light transition-colors"
>
<h3 class="text-2xl">$title$</h3>
<p
@ -30,7 +30,7 @@ title: "youwen wu"
</a>
</div>
<hr
class="max-w-[200px] border-0 h-1 dark:bg-accent-dark bg-accent-light rounded-lg px-2 group-hover:max-w-[250px] dark:group-hover:bg-secondary-dark group-hover:bg-secondary-light transition-all duration-400"
class="max-w-[200px] border-0 h-1 dark:bg-accent-dark bg-accent-light rounded-lg px-2 group-hover:max-w-[250px] dark:group-hover:bg-iris-dark group-hover:bg-iris-light transition-all duration-400"
/>
</li>
$endfor$

View file

@ -2,25 +2,21 @@
author: "Youwen Wu"
authorTwitter: "@youwen"
desc: "a purely functional...blog?"
image: "./images/gradient-ascent.jpg"
image: "./images/conditional-finality.png"
keywords: "haskell, blog, functional programming"
lang: "en"
title: "why I made my blog in haskell"
title: "a haskellian blog"
updated: "2024-05-25T12:00:00Z"
---
Welcome! This is the first post on _gradient ascent_ and also one that tests all
Welcome! This is the first post on _conditional finality_ and also one that tests all
of the features.
<img
alt="gradient ascent"
src="./images/gradient-ascent.jpg"
style="height: 200px; width: 100%; object-fit: cover"
alt="conditional finality"
src="./images/conditional-finality.png"
/>
I'll be writing about computers, code, math, video games, and whatever else
here.
> A monad is just a monoid in the category of endofunctors, what's the problem?
## haskell?
@ -59,11 +55,6 @@ The code highlighting is also generated by hakyll.
Haskell is a purely functional language with no mutable state. Its syntax
actually makes it pretty elegant for declaring routes and "rendering" pipelines.
I originally wanted to build this entire blog myself. I had a working version
with the Svelte framework, complete with GFM rendering, table of contents, KaTeX
math, code highlighting, static generation, and other goodies. However, it
seemed like a little too much work to maintain. I switched to hakyll because
1. Haskell is cool.
2. It comes with enough features that I don't feel like I have to build
everything from scratch.
@ -77,7 +68,7 @@ seemed like a little too much work to maintain. I switched to hakyll because
### speaking of math
We can have math inline, like so:
$\int_\infty^\infty \, e^{-x^2}\,dx = \sqrt{\pi}$. This site ships semantic
$\int_{-\infty}^\infty \, e^{-x^2}\,dx = \sqrt{\pi}$. This site ships semantic
MathML math with its HTML, and the MathJax script to the client.
It'd be nice if MathML could just be used and supported across all browsers, but

View file

@ -1,197 +0,0 @@
---
author: "Youwen Wu"
authorTwitter: "@youwen"
desc: "and the future of operating systems"
image: "./images/gradient-ascent.jpg"
keywords: "nix, nixos, functional programming, linux, unix"
lang: "en"
title: "a retrospective on NixOS"
updated: "2024-05-25T12:00:00Z"
---
Many people more knowledgeable than me have already written at length about the
virtues of NixOS and _declarative configuration_ and _immutability_ and such. I
doubt what I have to say is particularly novel to those already familiar with
Nix, but I'd like to discuss precisely what brings people to NixOS in the first
place.
Many people will introduce NixOS by first introducing the Nix package manager,
and immediately jumping into terms like _derivation_ and _immutability_ and
_reproducibility_ and whatnot. And while these are important concepts for
understanding the system at large, it's not very convincing for people looking
to try out the system. After all, most people don't (or at least shouldn't!)
choose their tools based on hype or purported benefits, but based the problems
that they help them solve.
Instead of immediately evangelizing about the virtues of Nix and NixOS, I'll
first motivate the reasons for why I chose a tool with exactly its properties
(but not to worry, the evangelizing will come later).
Essentially: allow me to introduce you to the
origins of the [NixOS God
Complex](https://www.reddit.com/r/NixOS/comments/kauf1m/dealing_with_post_nixflake_god_complex/).
---
My goals for my system are as follows:
- Allow my computing environment to exist on different computers at the same
time (essentially, sync up configurations between machines)
- Precisely control the software and services on my machine. I should be able
to obtain binaries of most things to save time, but be able to step into the
source and apply patches or configuration as desired
- For the OS to be absolutely unbreakable
- Never configure the system twice; once I solve a problem, I should have a
reproducible solution that solves it permanently
- Be able to backup my system configuration and quickly redeploy it whenever
needed
- Avoid janky solutions to these problems that introduce tech debt. I don't
want to have to rely on disk images or backups, I want to be able to create
fresh installations quickly
Essentially, I want to synchronize the configuration of my entire system across
multiple machines while maintaining a stable and usable system I'm not worried
will inadvertently fall apart with a routine system update. When I tweak and
mess with some settings on my desktop, I should be able to push to a `git`
repository and pull it down on my laptop and have the tweaks carried over. This
even includes system-level configuration like the applications installed,
system daemons, and other core system services.
I want a source and binary based distribution simultaneously. And I want a
self-documenting reproducible system where every tiny tweak is
deterministically applied. And I want to be able to install my configurations
onto a new computer, from scratch, in an installer, effectively creating my own
custom Linux distribution.
Oh, and I also want to solve the "works on my machine" problem, and never have
trouble using software someone else packaged and claims works on their end, but
fails on my computer.
All or even just a few of these goals seem unattainable to the typical Linux
user (not to mention those still on Windows and macOS $\dots$ _oh, the
horror!_). But I was in fact able to achieve all of them.
---
To begin, let's examine how one might try to approach these problems with the
common solutions.
Let's talk about sharing configuration among multiple computers first, which
can be thought of as some form of "settings sync".
Most people have encountered solutions to sychronizing configuration in two
ways: either the entire service is ran in the cloud, so it's really the _same_
environment accessed from multiple places (eg. Google Docs), or it's some often
half baked opaque solution involving you making an account and sending all your
settings to a sync server (eg. Mozilla Firefox).
The more technically minded may instead opt to create a "dotfiles" repository,
holding their vast collection of meticulously crafted configuration files.
These repos often come with a janky `install.sh` script that does its best to
install all the files into the correct place. This usually works the first
time, but trying to keep the installed dotfiles in sync with a central
repository is a whole other problem.
There are also dotfile manager like `chezmoi` or GNU Stow. I have not tried
these so I make no judgements on their utility for their intended purpose.
These dotfile management solutions may work well for managing configuration
files, but they both have the same issue: you also need to install the software
you're configuring!
The software and the configuration are fundamentally tied together; these are
not concerns to be separated. If the software is installed, it almost always
needs to be configured anyways. If the configuration exists, the software
should be installed. So a sane solution needs to both put the configuration in
the right place, _and_ set up the system's programs along with all their
dependencies!
So, the most obsessive *nix hackers reach for tools like
[Ansible](https://www.ansible.com/), that promise automatic configuration of
entire systems. Though Ansible was initially designed to deploy cloud servers
quickly through the Infrastructure-as-Code approach, some people opt to use it
for deploying and managing their systems quickly as well. I have not personally
tried it beyond playing with a few examples The consensus seems to be that it
seems to work fine for simple use cases but gets quite unwieldy for more
complex purposes (especially for personal systems, which aren't expected to be
as ephemeral as servers).
A system like Ansible combined with a system to manage configuration files
might be able to achieve a few of our goals. We can keep configuration in sync
between computers and we can quickly redeploy our system. But anyone who has
tried this will tell you that it's incredibly uncomfortable to use; our
existing operating systems are simply not designed to be managed in this
manner. Inevitably you will experience desynchronization between the
configuration and the actual state of the machine.
Also, this does not solve some of our other problems. We'll still need tools
like Docker to reproducibly build software and figure out a way to keep our
system stable.
If you agree with the premises I've laid out up to this point, that none of
these solutions provide a satisfying solution to our computing woes, you might
come to the conclusion that I've made. We need a solution that does _all of
it_. A unified tool for reliably deploying software and managing your system
configuration. And it must necessarily be declarative and reproducible, because
that is the only sane way to manage a system. Imagine working on a programming
project where recompiling with the same source code would non-deterministically
produce different results based on the environment! We should be able to write
files that declaratively and precisely specify the state of whole system, and
then be able to revert these files or tweak them with deterministic results
that don't leave behind any broken programs or files.
Well, [Nix](https://nixos.org/) is the _purely functional_ package manager
(i.e. declarative, reproducible), and NixOS is a Linux distribution that is
managed entirely by Nix. Essentially, Nix provides a solution to the problem of
_software deployment_, and in fact was purpose built to do so in Eelco
Dolstra's seminal [PhD
thesis](https://edolstra.github.io/pubs/phd-thesis.pdf). It effectively solves
the problem of "works on my machine" by _forcing_ the user to actually specify
all required dependencies. This makes it a little harder to write the initial
build configurations due to the strictness imposed. But the reward is that if a
piece of software builds on one machine, it's guaranteed to build on another.
NixOS is a system that takes the power of Nix and applies it to declaratively
configure an _entire Linux system_. All of the installed software and activated
services can be specified precisely using the Nix expression language, a purely
functional DSL used by Nix. And alongside the software, it also configures it,
effectively acting as a dotfile manager. Indeed, many core NixOS services and a
wide range of programs can be set up through _NixOS modules_, where the program
is installed and configured in the same place. (and many programs like `fzf`,
`btop`, etc have similar corresponding `home-manager` modules).
NixOS is also _immutable_, which means that the system cannot be modified after
it is built from the Nix files that declare it. How do you make changes to the
system then? Obviously, we just create a new system where the changed programs
and files are included, and the old ones are removed. But they are not deleted
from the hard drive, they still exist in the _Nix store_. So, the system can
provide precise atomic rollbacks between each "generation" of itself. Broke
your GRUB configuration so your system won't boot? Messed up your kernel
settings? Just select an older working generation from the boot menu and you
instantly have a working system again. You never worry about breaking things
during either routine or massive system updates.
And because the system is fully declarative, and modifying the system is done
only through modifying its Nix configuration files, you can version and sync
them up with Git. This solves the problem of keeping system environments in
sync; now, you truly only have to keep one repository of all your configuration
in sync, and all the software installation and deployment is handled for you by
a system designed precisely for that purpose.
This makes it possible for me to share common configuration between a multitude
of entirely distinct machines, including an `x86_64` desktop, an `x86_64`
laptop, an Apple Silicon Macbook running NixOS `aarch64` using [Asahi
Linux](https://asahilinux.org/), and the same Macbook running macOS with
`nix-darwin`, sharing `home-manager` configuration with NixOS. Specific
configuration necessary to adjust hardware-specific details between each
machines are isolated to the [hosts](./hosts) directory.
This works exceptionally well, evidenced by the fact that I have (almost) the
exact same environment across three separate machines, spanning two entirely
distinct CPU architectures.
In essence, the primary failure of deployment scripts, Ansible and the like is
that they are _imperative_ - they must specify precisely _how_ to set up the
system, down to minute details, whereas in a _declarative_ approach, the user
can simply specify what the system _should look like_, and abstractions take
care of the _how_. This is what NixOS does, and it gives you remote syncing,
versioning (via `git`), and rollbacks _for free_.

View file

@ -1,7 +1,7 @@
<!doctype html>
<html lang="$lang$">
<head>
<title>$title$ | gradient ascent</title>
<title>$title$ | conditional finality</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
@ -116,7 +116,7 @@
<a
href="/"
class="dark:hover:text-muted-dark hover:text-muted-light transition-all duration-500 text-nowrap tracking-wide"
><em>Gradient Ascent.</em></a
><em>Conditional Finality.</em></a
>
</h1>
<div
@ -126,18 +126,18 @@
<p class="mt-8 mb-3 px-1 italic font-light">
a web-log about computers, math, hacks, and all the rest.
</p>
<a class="text-sm external-link" href="https://youwen.dev"
<a class="text-sm text-iris-light dark:text-iris-dark hover:text-love-light dark:hover:text-love-dark" href="https://youwen.dev"
><em>by </em>Youwen Wu</a
>
<span class="ml-2 font-serif">|</span>
<button
id="theme-toggle"
class="ml-2 text-sm hover:bg-indigo-200 dark:hover:bg-violet-950 rounded-sm transition-colors p-1 duration-500"
class="ml-2 text-sm hover:text-accent-light dark:hover:text-muted-dark"
></button>
<span class="ml-2 font-serif">|</span>
<button
id="font-toggle"
class="ml-2 text-sm hover:bg-indigo-200 dark:hover:bg-violet-950 rounded-sm transition-colors p-1 duration-500"
class="ml-2 text-sm hover:text-accent-light dark:hover:text-muted-dark"
></button>
</header>
$body$
@ -149,14 +149,14 @@
&copy; 2024 Youwen Wu. Generated by
<a
href="https://jaspervdj.be/hakyll/"
class="external-link"
class="external-link-muted"
target="__blank"
>Hakyll.</a
>
View the source
<a
href="https://github.com/couscousdude/blog"
class="external-link"
class="external-link-muted"
target="__blank"
>on GitHub.</a
>
@ -164,7 +164,7 @@
<p class="text-sm leading-relaxed mt-2">
Content freely available under
<a
class="external-link"
class="external-link-muted"
target="__blank"
href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.en"
><span class="smallcaps">CC BY-NC-SA</span> 4.0</a

View file

@ -28,13 +28,13 @@ import Text.Pandoc.Options (
-- PERSONALIZATION
mySiteName :: String
mySiteName = "gradient ascent"
mySiteName = "conditional finality"
mySiteRoot :: String
mySiteRoot = "https://blog.youwen.dev"
myFeedTitle :: String
myFeedTitle = "gradient ascent"
myFeedTitle = "conditional finality"
myFeedDescription :: String
myFeedDescription = "on computers, hacks, math, and life"

View file

@ -10,24 +10,42 @@ module.exports = {
},
colors: {
primary: {
dark: "#e7e5e4",
//dark: "#e7e5e4",
light: "#44403c",
dark: "#e0def4",
//light: "#575279",
},
secondary: {
dark: "#4c1d95",
light: "#4338ca",
//dark: "#4c1d95",
//light: "#4338ca",
dark: "#1f1d2e",
light: "#fffaf3",
},
accent: {
dark: "#9ca3af",
light: "#78716c",
//dark: "#9ca3af",
//light: "#78716c",
dark: "#908caa",
light: "#797593",
},
muted: {
dark: "#6b7280",
light: "#a8a29e",
//dark: "#6b7280",
//light: "#a8a29e",
dark: "#6e6a86",
light: "#9893a5",
},
background: {
light: "#d6d3d1",
dark: "#101017",
//light: "#d6d3d1",
//dark: "#101017",
dark: "#191724",
light: "#faf4ed",
},
iris: {
dark: "#c4a7e7",
light: "#907aa9",
},
love: {
dark: "#eb6f92",
light: "#b4637a",
},
},
},