From: moo Date: Thu, 3 Sep 2026 23:28:42 +0000 (-0700) Subject: stuff X-Git-Url: https://git.taranathan.com/?a=commitdiff_plain;ds=inline;p=blog.git stuff --- diff --git a/content/blog/pipes.md b/content/blog/pipes.md new file mode 100644 index 0000000..32c2735 --- /dev/null +++ b/content/blog/pipes.md @@ -0,0 +1,45 @@ ++++ +title = "pipes" +date = 2026-06-22 ++++ + +Huh. I was just thinking about how cool a pipe operator would be in rust, and about method-chaining when I realized that they are both kind of the same thing! For example, look at these rust and gleam (a language with a very similar syntax): + +```rust +//rust +let result: Result = fallible_operation(); +let output = result + .map(add_one) + .map(add_one) + .map(add_one) + .unwrap_or(0); +``` + +
+ +```gleam +//gleam +let result: Result(Int) = fallible_operation() +let output = result + |> result.map(add_one) + |> result.map(add_one) + |> result.map(add_one) + |> result.unwrap(0) +``` + +When they are formatted this way, don't they look *pretttty* similar? That's because, they are, by definition, the exact same thing. If you look into the function signatures behind any `impl` method/function in rust, they all start with an `&self` or some variation because the dot notation is actually just syntax sugar. If I wanted to write out the rust example the long way, I could've done it like this: + +```rust +// the type of std::result::unwrap_or is fn(self, F) -> Result, +// but in dot notation the first argument is omitted, like in a pipe operator + +let result: Result = fallible_operation(); +let output = std::result::Result::unwrap_or( + std::result::Result::map( + std::result::Result::map( + std::result::Result::map(&result, add_one), add_one), add_one), + 0); +``` + +And the pipe operator in so many functional languages also serves the same purpose: as syntax sugar. Anyways, I just found this kind of neat, and my guess as to a little bit about why there isn't a pipe operator in rust yet, despite taking so much heavy influence from functional languages like OCaml. + diff --git a/public/blog/gleam/index.html b/public/blog/gleam/index.html index bb47f43..f255e33 100644 --- a/public/blog/gleam/index.html +++ b/public/blog/gleam/index.html @@ -31,7 +31,7 @@

gleam

2026-06-15

Last wednesday, when I was boarding my flight to Junior Men’s National Team field hockey tryouts(wish me luck!), I started to try out the Gleam programming language. It is really fascinating. It looks like rust(without mutability or imperativeness), but compiles down to erlang and javascript. It also has a bunch of quality of life features for functional programming that I would love to have in rust, like the pipe operator or the ease of its partial function application. For example, in gleam, you can just do this to partially apply a function:

-
fn add(x: Int, y: Int) -> Int {
+
fn add(x: Int, y: Int) -> Int {
   x + y
 }
 
@@ -40,16 +40,16 @@
   assert add_one(3) == 4
 }

It’s so simple! Also, the pipe operator works just like you’d expect from any other functional language:

-
fn main() {
+
fn main() {
   assert 5 == { 1 |> add_one |> add_three }
 }

I feel like they also made a couple design decisions in a pythonic manner. For example, in the code above, you can see that to specify and clarify order of operations, instead of using parentheses it uses curly braces. This is because like rust, gleam is an expression based language, and therefore, code blocks return values without having to manually insert a return statement. It may seem like this is just trying to be different just to be different, but I really like this, and is just an interesting consequence of being expression based, and it removes unnecessary options to do functionally the same thing. In fact, you can do this in rust(another expression based language) as well!

-
fn main() {
+
fn main() {
   let x = 3 * { 2 + 3 };
   assert_eq!(x, 15);
 }

Now, back to the story. So I was having a bunch of stupid problems with the airport wifi, and my phone’s hotspot was bugging out as well, so I was completely offline for like 5 hrs, even before I got on the flight. (this was also kinda because my flight got delayed by 4 hrs, because they switched the plane we were going to be taking to a different one.) So during that time, I started to try to see what I could get done with the language. Gleam’s package manager/build tool/whatever cli is really nice, and it caches all the data of dependencies added to the project previously. So, basically what I did was before I left home, I added a bunch of packages that I saw were pretty commonly used in the community, and a web framework. So what I did while off the internet was just tinker around with the language and the libraries, trying to figure out what to do based on LSP Hover tips and examples. I wanted to figure out how to do argument parsing and a simple web application. For the argument parsing thing, I kinda just messed around with the argv library, and never actually tried out glint, the more full featured argument parser. The entire argv library is basically just a single function, argv.load(), that returns a list of strings, which are the arguments to the program. But this really beautifully showcases some of the power of gleam’s pattern matching:

-
pub fn main() {
+
pub fn main() {
   let args: List(String) = argv.load().arguments
   case args {
     ["greet", name] -> io.println("hello " <> name <> "!")
@@ -59,7 +59,7 @@
 }

I think that this is probably my favorite way to do simple command line argument parsing, even if it isn’t the most effective or feature complete. I guess if you want to do that, there is the glint library that I mentioned previously, but I haven’t really got around to exploring that yet.

The second part of my little adventure was trying to make a little web app in the programming language. I ended up learning about an actual frontend framework that uses the fact that the language can compile to Javascript (lustre), but I already had hacked together a simple html/css/js frontend by that point. The finished project is at files.taranathan.com, so you guys can check out what it ended up like there. (Side note: During the process, I ended up moving a lot of the things I was hosting on my web server from apache2 to Caddy, and it was really interesting! I think caddy is really cool, and it is sooooo much simpler to configure for the really simple things I am doing. I basically just host a wordpress site, run a gitweb site(cgi), run my site(just static hosting), and a couple of reverse proxies to expose my web-related projects. All I had to do was recompile caddy from source with a module for cgi.) So, if you went to the link, you would see that it is just a really simple file hosting/sharing site. The whole page is basically just a form asking for a file, a file name, and a password(I might give it to you if you ask really nicely \(°^°)/). So this is basically the entry point of the web server. The argument file_path is the path to where to store and serve the files from, and passwords is just a list of the valid passwords(i know, not very secure).

-
fn web(file_path: String, passwords: List(String)) -> Nil {
+
fn web(file_path: String, passwords: List(String)) -> Nil {
   wisp.configure_logger()
 
   let secret_key_base =
@@ -79,14 +79,14 @@
   process.sleep_forever()
 }

The router module is mine, and I’ll talk about it later. This might look pretty wierd to you, if you come from an imperative or OOP background, so I’ll go through it line by line. First we configure the logger, and then generate a secret_key_base either from an env variable or a random string. Then, we get to the let assert Ok(_) = .... This basically means that the result of the expression in front of it is of the result type/enum, and it must be of the Ok variant, and we do not care about what is inside of the Ok. Another thing that might be confusing is the router.handle_request(_, file_path, passwords). As I wrote about above, this is an example of partial function application. The actual function signature of router.handle_request is:

-
pub fn handle_request(
+
pub fn handle_request(
   req: wisp.Request,
   file_path: String,
   passwords: List(String),
 ) -> wisp.Response {

So what we are doing here is we are basically filling in file_path and passwords and changing the function signature into fn(wisp.Request) -> wisp.Response. And then after that, we just pipe it into a couple of builder functions and then start it. After starting it, we tell the main process to sleep forever, because mist.start starts the process on another thread.

Now lets take a look at the main route handler function:

-
pub fn handle_request(
+
pub fn handle_request(
   req: wisp.Request,
   file_path: String,
   passwords: List(String),
@@ -108,7 +108,7 @@
   }
 }

So, the first line basically just sets up some basic middleware stuff. The use statement in gleam is pretty wierd and hard to wrap your head around, but it really is just some syntax sugar. For example, if we just removed the use statement from our function, it would look like this:

-
pub fn handle_request(
+
pub fn handle_request(
   req: wisp.Request,
   file_path: String,
   passwords: List(String),
diff --git a/public/blog/index.html b/public/blog/index.html
index 5a530d4..0ee3a6d 100644
--- a/public/blog/index.html
+++ b/public/blog/index.html
@@ -31,15 +31,21 @@
   
  • - extra photos from germany + germany

    — 2026-07-24

  • - germany + extra photos from germany

    — 2026-07-24

    +
  • + +
  • + pipes +

    — 2026-06-22

    +
  • diff --git a/public/blog/pipes/index.html b/public/blog/pipes/index.html new file mode 100644 index 0000000..cbf1960 --- /dev/null +++ b/public/blog/pipes/index.html @@ -0,0 +1,94 @@ + + + + + + pipes + + + + + +
    +
    +
    +
    + +
    +
    +

    My Blog

    + +
    + +
    + +
    +

    pipes

    +

    2026-06-22

    +

    Huh. I was just thinking about how cool a pipe operator would be in rust, and about method-chaining when I realized that they are both kind of the same thing! For example, look at these rust and gleam (a language with a very similar syntax):

    +
    //rust
    +let result: Result<i32> = fallible_operation();
    +let output = result
    +  .map(add_one)
    +  .map(add_one)
    +  .map(add_one)
    +  .unwrap_or(0);

    +
    //gleam
    +let result: Result(Int) = fallible_operation()
    +let output = result
    +  |> result.map(add_one)
    +  |> result.map(add_one)
    +  |> result.map(add_one)
    +  |> result.unwrap(0)
    +

    When they are formatted this way, don’t they look pretttty similar? That’s because, they are, by definition, the exact same thing. If you look into the function signatures behind any impl method/function in rust, they all start with an &self or some variation because the dot notation is actually just syntax sugar. If I wanted to write out the rust example the long way, I could’ve done it like this:

    +
    // the type of std::result::unwrap_or is fn(self, F) -> Result<U, E>,
    +// but in dot notation the first argument is omitted, like in a pipe operator
    +
    +let result: Result<i32> = fallible_operation();
    +let output = std::result::Result::unwrap_or(
    +  std::result::Result::map(
    +  std::result::Result::map(
    +  std::result::Result::map(&result, add_one), add_one), add_one),
    +  0);
    +

    And the pipe operator in so many functional languages also serves the same purpose: as syntax sugar. Anyways, I just found this kind of neat, and my guess as to a little bit about why there isn’t a pipe operator in rust yet, despite taking so much heavy influence from functional languages like OCaml.

    +
    +
    + +
    +
    + +
    +
    +
    +
    + + + + + diff --git a/public/miniblog/index.html b/public/miniblog/index.html index 98e70a5..db0a0d9 100644 --- a/public/miniblog/index.html +++ b/public/miniblog/index.html @@ -3,7 +3,7 @@ - Miniblog/journal posts + Miniblog/journal posts @@ -27,7 +27,7 @@
    -

    Miniblog/journal posts

    +

    Miniblog/journal posts

    • diff --git a/public/miniblog/pipes/index.html b/public/miniblog/pipes/index.html index 27fe4eb..292f5eb 100644 --- a/public/miniblog/pipes/index.html +++ b/public/miniblog/pipes/index.html @@ -31,14 +31,14 @@

      pipes

      2026-06-22

      Huh. I was just thinking about how cool a pipe operator would be in rust, and about method-chaining when I realized that they are both kind of the same thing! For example, look at these rust and gleam (a language with a very similar syntax):

      -
      //rust
      +
      //rust
       let result: Result<i32> = fallible_operation();
       let output = result
         .map(add_one)
         .map(add_one)
         .map(add_one)
         .unwrap_or(0);

      -
      //gleam
      +
      //gleam
       let result: Result(Int) = fallible_operation()
       let output = result
         |> result.map(add_one)
      @@ -46,7 +46,7 @@
         |> result.map(add_one)
         |> result.unwrap(0)

      When they are formatted this way, don’t they look pretttty similar? That’s because, they are, by definition, the exact same thing. If you look into the function signatures behind any impl method/function in rust, they all start with an &self or some variation because the dot notation is actually just syntax sugar. If I wanted to write out the rust example the long way, I could’ve done it like this:

      -
      // the type of std::result::unwrap_or is fn(self, F) -> Result<U, E>,
      +
      // the type of std::result::unwrap_or is fn(self, F) -> Result<U, E>,
       // but in dot notation the first argument is omitted, like in a pipe operator
       
       let result: Result<i32> = fallible_operation();
      diff --git a/public/sitemap.xml b/public/sitemap.xml
      index 0812086..3f3d310 100644
      --- a/public/sitemap.xml
      +++ b/public/sitemap.xml
      @@ -22,6 +22,10 @@
               https://taranathan.com/blog/gleam/
               2026-06-15
           
      +    
      +        https://taranathan.com/blog/pipes/
      +        2026-06-22
      +    
           
               https://taranathan.com/blog/second/
               2026-06-01
      diff --git a/templates/main-page.html b/templates/main-page.html
      deleted file mode 100644
      index 775e502..0000000
      --- a/templates/main-page.html
      +++ /dev/null
      @@ -1,5 +0,0 @@
      -{% extends "base.html" %}
      -
      -

      -wassup -