Master High School Sweetheart in Gleam: Complete Learning Path

a close up of a computer screen with code on it

Master High School Sweetheart in Gleam: Complete Learning Path

This guide provides a comprehensive deep-dive into string manipulation and formatting in Gleam, a critical skill for any developer. We will explore the core concepts required to build robust text-processing functions, using the "High School Sweetheart" module from the exclusive kodikra.com curriculum as our practical foundation.


The Art of the Perfect String: Why Formatting Matters

Ever felt lost trying to piece together different bits of text into a perfectly formatted message? You're not alone. In programming, whether you're generating a user welcome email, creating a report, or just printing a log message, manipulating strings is a task you'll perform daily. It seems simple on the surface, but one misplaced space or an unhandled edge case can lead to bugs that are both frustrating and unprofessional.

Imagine trying to format a formal letter. You need to handle names, dates, and specific salutations, ensuring every part is aligned and pristine. This is precisely the challenge we'll conquer in Gleam. This guide promises to take you from zero to hero in Gleam string manipulation, transforming you into a developer who can confidently and elegantly handle any text-based data that comes your way. We'll break down every function, explore best practices, and build a complete solution together.


What is the "High School Sweetheart" Module?

The "High School Sweetheart" module, a cornerstone of the kodikra Gleam learning path, is a practical set of challenges designed to teach fundamental string manipulation techniques. It simulates the task of creating a formatted love letter, requiring you to implement several small, focused functions that work together to produce a final, polished output.

At its core, this module is about breaking a large problem (formatting a letter) into smaller, manageable pieces. You'll learn to trim whitespace, extract specific characters, combine names to form initials, and format multi-line text blocks. It's the perfect introduction to functional programming principles like function composition and immutability, all within the safe and statically-typed environment of Gleam.

The Core Concepts You Will Master

This module isn't just about solving one problem; it's about building a toolkit of skills. Here are the key concepts we will explore in depth:

  • String Basics in Gleam: Understanding how Gleam handles strings as immutable UTF-8 encoded binaries.
  • The gleam/string Standard Library: Leveraging powerful, built-in functions to avoid reinventing the wheel. We'll focus on functions like string.trim, string.first, string.last, and the concatenation operator <>.
  • Function Definition and Signatures: Writing clean, type-safe functions with explicit input and output types.
  • Function Composition: Using the pipe operator |> to chain functions together for elegant and readable data transformations.
  • Pattern Matching: Safely handling optional values (Result and Option types) that are returned by string functions.

How to Approach String Manipulation in Gleam

Tackling string formatting in Gleam requires a methodical approach. The language's strong type system and functional paradigm guide you toward writing code that is not only correct but also easy to read and maintain. Let's walk through the step-by-step process of building the required functionality.

Step 1: Setting Up Your Gleam Project

Before writing any code, you need a Gleam project. The Gleam build tool makes this incredibly simple. Open your terminal and run the following commands.

# Create a new Gleam project
gleam new my_formatter

# Navigate into the project directory
cd my_formatter

# You can run tests to ensure everything is set up correctly
gleam test

This creates a standard project structure with a src directory for your code and a test directory for your tests. All our logic will go into a file like src/my_formatter.gleam.

Step 2: Trimming Whitespace with string.trim

A common source of bugs is extraneous whitespace. A user might accidentally type " John Smith " instead of "John Smith". The gleam/string module provides the perfect tool for this: string.trim.

import gleam/string

pub fn clean_name(name: String) -> String {
  string.trim(name)
}

// Usage Example in a test or main function:
// let messy_name = "  Alice   "
// let cleaned_name = clean_name(messy_name)
// cleaned_name will be "Alice"

This function takes a String and returns a new String with all leading and trailing whitespace removed. Because strings are immutable in Gleam, the original string is left untouched.

Step 3: Extracting Initials

Next, we often need to extract parts of a string. Let's create a function to generate initials from two names. This involves getting the first letter of each name and combining them.

The string.first function is ideal, but it doesn't return a String directly. It returns a Result(String, Nil), because an empty string has no first character. We must handle this possibility using pattern matching.

import gleam/string
import gleam/result

pub fn first_letter(name: String) -> String {
  let cleaned_name = string.trim(name)

  case string.first(cleaned_name) {
    Ok(letter) -> string.uppercase(letter)
    Error(Nil) -> "" // Return an empty string if the name is empty
  }
}

pub fn initials(name1: String, name2: String) -> String {
  let initial1 = first_letter(name1)
  let initial2 = first_letter(name2)

  initial1 <> " + " <> initial2
}

// Usage Example:
// let result = initials("  jane doe ", "  john smith  ")
// result will be "J + J"

Here, we define a helper function first_letter that safely extracts and uppercases the first letter. The initials function then composes this logic to produce the final formatted string.

This flow demonstrates a core functional programming pattern:

    ● Start with raw names
    │   (e.g., "  jane doe  ", "  john smith  ")
    │
    ▼
  ┌───────────────────┐
  │ For each name...  │
  └─────────┬─────────┘
            │
            ▼
      ┌───────────┐
      │ string.trim │
      └─────┬─────┘
            │
            ▼
    ┌───────────────────┐
    │ string.first      │
    │ (Returns Result)  │
    └─────────┬─────────┘
              │
              ▼
        ◆ Is it Ok(letter)?
       ╱                   ╲
      Yes                   No
      │                     │
      ▼                     ▼
┌───────────────┐      ┌───────────┐
│ string.uppercase │      │ Return "" │
└───────────────┘      └───────────┘
      │                     │
      └─────────┬───────────┘
                │
                ▼
          ┌─────────────┐
          │ Combine with  │
          │ " + "         │
          └──────┬──────┘
                 │
                 ▼
            ● End Result
              (e.g., "J + J")

Step 4: Building the Letter Body

Now, let's combine our functions to build the different parts of the letter. The task involves creating a salutation line, the main body, and a signature line. We can use the string concatenation operator <> extensively here.

The beauty of our previous work is that we can now reuse the initials function and other helpers to build more complex strings without rewriting logic.

// Assuming the `initials` and `first_letter` functions from above

pub fn pair(name1: String, name2: String) -> String {
  let formatted_initials = initials(name1, name2)

  "          " <> "******" <> "
          " <> "**    **" <> "
          " <> "** " <> formatted_initials <> " **" <> "
          " <> "**    **" <> "
          " <> "******" <> "
"
}

pub fn greet(recipient: String) -> String {
  "Hello, " <> string.trim(recipient) <> "!"
}

pub fn sign(sender: String) -> String {
  "Sincerely,
" <> "
" <> string.trim(sender)
}

// Combining everything to form the letter
pub fn create_letter(recipient: String, sender: String) -> String {
  greet(recipient) <> "

" <> pair(recipient, sender) <> "

" <> sign(sender)
}

This is the logical flow for generating the complete letter:

    ● Start with recipient and sender names
    │
    ├───────────┐
    │           │
    ▼           ▼
┌─────────┐   ┌─────────┐
│ greet() │   │ sign()  │
└────┬────┘   └────┬────┘
     │             │
     │             ▼
     │         ┌────────────┐
     │         │ pair()     │
     │         │ ╭──────────╮
     │         │ │ initials() │
     │         │ ╰──────────╯
     │         └──────┬─────┘
     │                │
     └────────┬───────┘
              │
              ▼
      ┌──────────────────┐
      │ Combine all parts│
      │ with newlines    │
      │      ( "<>" )      │
      └─────────┬────────┘
                │
                ▼
           ● Final Letter String

This approach, where small, pure functions are combined to create larger functionality, is central to Gleam and functional programming. It makes the code easy to test, reason about, and reuse.


Where Are These Skills Used? Real-World Applications

The techniques learned in the "High School Sweetheart" module are not just academic exercises. They are directly applicable to countless real-world programming scenarios.

  • Web Development: When a user signs up, you need to clean their input (trimming names, emails), format welcome messages ("Hello, John!"), and generate user-friendly URLs or "slugs" from article titles (e.g., "My Awesome Post" -> "my-awesome-post").
  • Data Processing & ETL: When processing data from CSV files or APIs, you constantly need to parse and clean strings. This includes removing unwanted characters, splitting lines into columns, and normalizing data for storage in a database.
  • Command-Line Interface (CLI) Tools: Building CLI tools involves creating beautifully formatted output. You might need to generate tables, progress bars, or colorful status messages, all of which rely heavily on precise string concatenation and padding.
  • Generating Reports: Whether creating a PDF, HTML, or plain text report, you'll be piecing together data fields, headers, footers, and formatted numbers into a structured document.
  • API Responses: Crafting specific JSON or XML responses often requires building strings dynamically based on application state or database queries.

Mastering these fundamentals in Gleam provides a solid foundation for building complex, real-world applications with confidence.


Common Pitfalls and Best Practices

While string manipulation seems straightforward, there are common traps developers fall into. Adhering to best practices ensures your code is robust, readable, and performant.

Best Practice Common Pitfall (Anti-Pattern)
Always trim user input. Assume all external data is "dirty" and clean it at the boundary of your application. Trusting input. Assuming a name string won't have leading/trailing spaces, leading to formatting errors or failed database lookups.
Use pattern matching for safe access. Functions like string.first return a Result. Use a case expression to handle both success and failure gracefully. Ignoring potential failures. Assuming a string is never empty and trying to access its first character directly, which would lead to a compile-time error in a language like Gleam that forces you to handle it.
Compose small, pure functions. Create reusable helpers like first_letter that do one thing well. This improves testability and readability. Writing monolithic functions. Putting all trimming, slicing, and concatenation logic into one giant function that is hard to debug and impossible to reuse.
Leverage the pipe operator |> for clarity. For multi-step transformations, a pipeline is often more readable than nested function calls. E.g., name |> string.trim |> string.uppercase. Deeply nested function calls. Writing string.uppercase(string.trim(name)) can become hard to read as more steps are added.
Understand Unicode. Gleam strings are UTF-8. Be mindful that a "character" can be multiple bytes. Standard library functions handle this correctly. Assuming ASCII. Manually iterating over bytes and assuming one byte equals one character can break your code for non-English text.

Your Learning Path: The "High School Sweetheart" Module

This module is designed to be completed in a specific order to build your skills progressively. Start with the foundational exercise to solidify your understanding of the core concepts.

  1. High School Sweetheart: This is the main challenge where you will implement all the functions discussed above. It's the perfect starting point to apply your knowledge of the gleam/string module and function composition.
    Learn High School Sweetheart step by step

By completing this module from the kodikra learning curriculum, you will gain the practical experience needed to handle any string manipulation task in your future Gleam projects.


Frequently Asked Questions (FAQ)

Why does string.first return a Result(String, Nil) instead of just a String?

This is a core feature of Gleam's commitment to type safety. A function must account for all possible inputs. If you pass an empty string ("") to string.first, there is no first character to return. Instead of crashing or returning a special value like null, Gleam returns a Result type. The Error(Nil) variant explicitly tells the compiler, "This operation failed, and here's why (in this case, for no specific reason other than it was not possible)." This forces you, the developer, to handle the failure case, preventing runtime errors.

What is the difference between the <> operator and string.append?

Functionally, they achieve the same goal: concatenating two strings. The <> operator is syntactic sugar for the string.append function. In Gleam, most operators are just functions that can be used in an infix position. Using "a" <> "b" is generally preferred for readability over string.append("a", "b"), especially when chaining multiple strings together. Under the hood, they compile to the same efficient Erlang/JavaScript string concatenation.

Are strings in Gleam efficient? What happens when I concatenate many strings?

Gleam strings are immutable and are backed by the highly optimized string implementations of its target platforms (Erlang VM and JavaScript). When you concatenate strings, a new string is created. For a few concatenations, this is extremely fast. If you are building a very large string from thousands of smaller pieces in a loop, it can be more efficient to build a list of strings and then use string.join at the end. For most common use cases, like the ones in this module, simple concatenation with <> is perfectly efficient and readable.

How does Gleam handle Unicode and characters like emojis?

Gleam strings are UTF-8 encoded, meaning they have excellent built-in support for Unicode, including emojis and characters from various languages. Functions in the standard library, like string.first or string.length, are Unicode-aware. For example, string.length("✨") correctly returns 1, because it counts grapheme clusters (what a human perceives as a single character), not the underlying bytes. This is a major advantage that helps you avoid common internationalization bugs.

What is the pipe operator |> and how would I use it here?

The pipe operator |> is a powerful tool for improving readability in functional code. It takes the result of the expression on its left and passes it as the first argument to the function on its right. For example, instead of writing string.uppercase(string.trim(name)), you could write:

import gleam/string

pub fn format_name(name: String) -> String {
  name
  |> string.trim
  |> string.uppercase
}

This creates a clear, top-to-bottom data pipeline that is often much easier to read and understand than deeply nested function calls.

Can I modify a string in place in Gleam?

No, you cannot. All data structures in Gleam, including strings, are immutable. This means that once a string is created, it can never be changed. Functions like string.trim or the <> operator do not modify the original string; they always return a new, modified string. This immutability helps prevent a whole class of bugs related to shared mutable state, making code easier to reason about and safer in concurrent environments.


Conclusion: Your Journey to String Mastery

You have now explored the essential theory and practice of string manipulation in Gleam. By understanding the gleam/string module, embracing immutability, and composing small, pure functions, you've built a powerful mental model for solving complex text-formatting problems. The "High School Sweetheart" module is more than just an exercise; it's a practical application of functional principles that builds a foundation for all your future Gleam development.

With these skills, you are now equipped to handle data cleaning, report generation, web development tasks, and more. Continue to practice, explore other functions in the standard library, and apply these patterns to your own projects. Your journey to becoming a proficient Gleam developer is well underway.

Disclaimer: The code and concepts discussed are based on Gleam v1.3.0 and its standard library. As Gleam evolves, specific function names or behaviors might change. Always refer to the official Gleam documentation for the most current information.

Back to Gleam Guide

Return to the Learning Roadmap


Published by Kodikra — Your trusted Gleam learning resource.