Chapter 3: Your own types

Pizza pricing

  • recursive types
  • maps
  • ?

ExtraSauce(Pizza) holds another pizza, so a pizza can be wrapped any number of times. The price function peels one layer per call.

%{Margherita: 7, …} is a map literal, compiled to dict.from_list.

dict.get(price_map, p)? uses the ? operator: if the lookup is Ok, you get the value; if it is Error, the whole function returns that error immediately. It works in the middle of an expression, here even inside a case branch.

Open in playground
import gleam/dict

pub type Pizza {
  Margherita
  Caprese
  Formaggio
  ExtraSauce(Pizza)
  ExtraToppings(Pizza)
}

def price_map() {
  %{
    Margherita: 7,
    Caprese: 9,
    Formaggio: 10,
  }
}

def calc_pizza_price(p: Pizza, price_map, acc: Int) {
  case p {
    ExtraSauce(s) -> calc_pizza_price(s, price_map, acc + 1)
    ExtraToppings(s) -> calc_pizza_price(s, price_map, acc + 2)
    _ -> acc + dict.get(price_map, p)? |> Ok
  }
}

def pizza_price(p: Pizza) {
  case calc_pizza_price(p, price_map(), 0) {
    Ok(price) -> price
    _ -> panic as "Invalid pizza"
  }
}

pub def main() {
  echo pizza_price(ExtraToppings(ExtraSauce(ExtraSauce(Margherita))))
}

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