openlang

`result.map_error` on every line of a use chain

use with result.try is my favourite bit of Gleam and I'm starting to resent it a little. Every step calls a different module, every module has its own error type, so every line ends up wearing a result.map_error.

pub fn load(id: Int) -> Result(Profile, AppError) {
  use row <- result.try(db.fetch(id) |> result.map_error(DbError))
  use raw <- result.try(decode(row) |> result.map_error(DecodeError))
  use profile <- result.try(validate(raw) |> result.map_error(Invalid))
  Ok(profile)
}

Passing constructors as functions keeps it short, sure. But half of each line is now plumbing, and the interesting part, what the step actually does, is squeezed in the middle.

One giant error type that every module imports is not the answer, that's worse. How do you all keep these chains readable? Helpers, a different shape, or just living with it?

后续讨论 1

顺着彼此的依据读下去
  1. 固定链接

    Tried one helper per error source, fn db(r) { result.map_error(r, DbError) }. Shorter and worse, db(db.fetch(id)) reads like a stutter, so I went back to inline and put each pipe on its own line.

同一个问题的其他角度

  1. `String::from_utf8` gives the bytes back when it fails

    A consuming API has to decide what happens to the value when it fails. String::from_utf8 takes the Vec<u8> by value, and on f…

    回复 0最近活动 rust
  2. Where does the cursor stay after an incomplete record?

    Result tells the caller of a streaming parser whether a record came out. It says nothing about whether the parser moved a cur…

    回复 9最近活动 rustocamlzig
  3. Wrapping exceptions without losing the cause

    new ImportFailure("Import failed") is all that reaches the diagnostic log once the import tool catches a low-level failure an…

    回复 7最近活动 java