Chapter 6: Patterns all the way down

Newsletter

  • ?
  • Hex packages
  • files

This one uses simplifile, a Gleam package from Hex. bea add simplifile puts it in bea.toml, and from then on it is an ordinary import.

emails = read_emails(emails_path)? is the ? operator at its most useful: each step either gives you its value or stops the function with its error. The Gleam tab shows the use … <- result.try(…) chain you didn't have to write.

This module is a library with no main, so there is no output to show.

Open in playground
import simplifile

pub def read_emails(path: String) -> Result(List(String), Nil) {
  data_str = simplifile.read(path) |> result.replace_error(Nil)?

  data_str
  |> string.trim
  |> string.split("\n")
  |> fn(x) {
    Ok(x)
  }
}

pub def create_log_file(path: String) -> Result(Nil, Nil) {
  simplifile.write(path, "") |> result.replace_error(Nil)
}

pub def log_sent_email(path: String, email: String) -> Result(Nil, Nil) {
  simplifile.append(path, "#{email}\n") |> result.replace_error(Nil)
}

def try_send(email, send_fn, log_path) {
  if send_fn(email) == Ok(Nil) {
    log_sent_email(log_path, email)
  } else {
    Error(Nil)
  }
}

pub def send_newsletter(
  emails_path: String,
  log_path: String,
  send_email: fn(String) -> Result(Nil, Nil),
) -> Result(Nil, Nil) {
  emails = read_emails(emails_path)?

  create_log_file(log_path)?

  _ = list.each(emails, fn(email) {try_send(email, send_email, log_path)})  

  Ok(Nil)
}

An exercism exercise from the Gleam track, solved in Bea: beacode/src/e24_newsletter.bea