Chapter 5: Collections

Weather ranking

  • multi-clause on several arguments
  • Order

compare_temperature matches on both arguments at once. Each clause handles one combination of units, converts, and calls itself again until both are Celsius.

list.sort(cities, _) is a function capture: the _ marks where the piped value goes.

Open in playground
import gleam/float
import gleam/list
import gleam/order.{type Order}

pub type Temperature {
  Celsius(Float)
  Fahrenheit(Float)
}

pub type City {
  City(name: String, temperature: Temperature)
}

def fahrenheit_to_celsius(fh: Float) -> Float {
  fh -. 32.0 /. 1.8
}

def compare_temperature(t1: Temperature, t2: Temperature) -> Order 

def compare_temperature(Fahrenheit(a), Fahrenheit(b)) {
  compare_temperature(fahrenheit_to_celsius(a) |> Celsius, fahrenheit_to_celsius(b) |> Celsius)
}

def compare_temperature(Fahrenheit(a), b) {
  compare_temperature(fahrenheit_to_celsius(a) |> Celsius(), b)
}

def compare_temperature(a, Fahrenheit(b)) {
  compare_temperature(a, fahrenheit_to_celsius(b) |> Celsius())
}

def compare_temperature(Celsius(t1), Celsius(t2)) {
  float.compare(t1, t2)
}

def sort_cities_by_temperature(cities: List(City)) -> List(City) {
  fn(a: City, b: City) {
    compare_temperature(a.temperature, b.temperature) 
  }
  |> list.sort(cities, _)
}

pub def main() {
  echo fahrenheit_to_celsius(72.5)
  echo compare_temperature(Celsius(32.1), Celsius(21.4))
  echo sort_cities_by_temperature(
    [
      City(name: "London", temperature: Celsius(30.5)),
      City(name: "Paris", temperature: Fahrenheit(82.1))
    ]
  )
}

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