Notes on codes, projects and everything

Learning a new language for more than 2 months (feat. Exercism)

Usually I take about a week to learn a new language so I can start doing some real work with it. After all a programming language (at least the high level and dynamic ones) is just assignment, calculation, branching, looping and reuse (and in certain cases, concurrency/parallelism, not gonna dive deep in defining the difference though). Well, that was true until I started learning Rust, partly for my own leisure.

I still don’t feel comfortable writing a complete Rust code.

Though I really like the language.

So in my current day job, some of my colleagues are writing mainly Golang code. I tried learning it for a while, but considering I am coming from Python, I hated it so much (and I don’t already love Python enough, mainly due to the limitations of lambda). Yes, it gets the job done, however it just feels very … raw, and overly simplified. Being a mostly functional person, the limitation on how to express an idea is frustrating (as if the statically typed part is not bad enough).

This is not a post that objectively tells why Golang sucks, it is just purely not something I would code in. I ended up continue writing code in Python because it makes more sense for the work I do.

Throughout the years, the team discussed on and off about Rust. Then I finally gave it a more serious look early this year. However it was only until around June I started to put in time and effort to go through the documentation. Meanwhile, just to practice purpose I found Exercism and found it good enough to be a 4Clojure equivalent to other languages.

Then exercism went through a redesign, not too long after I started to put in effort in solving the puzzles.

And came back with a mentor system that I still don’t fully appreciate (though I signed up to be one).

Learning Rust is both fun, and frustrating. Being a high-level and dynamically typed language programmer, I technically do not really need it. So being safe, faster is not something I find appealing. High level languages are not really known for being fast, though they are mostly safe anyway.

So I continue solving more programming puzzles/katas/exercises, and started to hit walls. The thing I like about exercism post redesign is the separation between core and optional exercises. The core exercises are usually there for the learners to learn about concepts, one at a time an it is a good enough mix of maths and programming problem (don’t bother to be solving complicated mathematics problems WHILE learning a new language here).

Next I will list some notable exercises with notes.

Pythagorean triplet

I am not a mathematician, so to me the question screams loop, loop and more looping to me. Find the sum of two squared numbers that is equal to another squared number, and the total of these three numbers is 1000. So in my early iterations I submitted this

pub fn find() -> Option<u32> {
    let mut result: u32 = 0;

    for a in 0u32.. {
        if a < 998 {
            for b in (a + 1u32).. {
                if a + b < 999 {
                    for c in (b + 1u32).. {
                        if a.pow(2) + b.pow(2) == c.pow(2) && a + b + c == 1000 {
                            result = a * b * c;
                            break;
                        } else if a + b + c > 1000 {
                            break;
                        }
                    }
                } else {
                    break;
                }
            }
        } else {
            break;
        }
    }

    Some(result)
}

Yea, it is rather fugly to look at. Then it became the following version because my mentor at the time told me that it could be done without all the excessive branching. (I obviously didn’t care much about efficiency)

pub fn find() -> Option<u32> {
    let mut result: Option<u32> = None;

    for a in 0u32..998 {
        for b in (a + 1u32)..(999 - a) {
            for c in (b + 1u32)..(1001 - a - b) {
                if a.pow(2) + b.pow(2) == c.pow(2) && a + b + c == 1000 {
                    result = Some(a * b * c);
                    break;
                }
            }
        }
    }

    result
}


Much cleaner, but was told I didn't need looping for the third number since I already know what it is if I have the first two.


pub fn find() -> Option<u32> {
    let mut result: Option<u32> = None;

    for a in 0u32..998 {
        for b in (a + 1u32)..(999 - a) {
            let c = 1000 - a - b;

            if a.pow(2) + b.pow(2) == c.pow(2) {
                result = Some(a * b * c);
                break;
            }
        }
    }

    result
}

Good enough, not the most efficient solution but got a green light to move on. I still don't like it personally as it doesn't look very functional enough and after a few months I re-attempted again.

pub fn find() -> Option<u32> {
    (1u32..998)
        .filter_map(|a| {
            (a + 1..999 - a)
                .filter_map(|b| {
                    let c = 1000 - a - b;

                    match a.pow(2) + b.pow(2) == c.pow(2) {
                        true => Some(a * b * c),
                        false => None,
                    }
                })
                .next()
        })
        .next()
}

Slightly cleaner though probably not as easy to interpret (depending on who you ask), but definitely could be done better. However I do appreciate the help from my mentor.

leave your comment

name is required

email is required

have a blog?

This blog uses scripts to assist and automate comment moderation, and the author of this blog post does not hold responsibility in the content of posted comments. Please note that activities such as flaming, ungrounded accusations as well as spamming will not be entertained.

Pings

Click to change color scheme