Skip to content

Commit 4935d01

Browse files
Apply suggestions from code review
Co-authored-by: Thanh Le <lenguyenthanh@hotmail.com>
1 parent cb065da commit 4935d01

File tree

1 file changed

+9
-9
lines changed

1 file changed

+9
-9
lines changed

collections/_posts/2025-08-17-custom-error-types.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,23 +52,23 @@ enum ParseError:
5252
def parse[F[_]](input: String)(using Raise[F, ParseError], Monad[F]): F[Result] =
5353
// do some hardcore parsing
5454
if missingBracket then
55-
UnclosedBracket.raise[F]
55+
UnclosedBracket.raise[F, Result]
5656
else if missingSemicolon then
57-
MissingSemicolon.raise[F]
57+
MissingSemicolon.raise // we can rely on type inference and omit extra typings
5858
else
5959
result.pure[F]
6060

6161
// use allow/rescue like try/catch to create scoped error handling
62-
val program: IO[Result] = Handle.allow[ParseError]:
62+
val program: IO[Unit] = Handle.allow[ParseError]:
6363
for
64-
x <- parse(inputX)
64+
x <- parse[IO](inputX)
6565
y <- parse(inputY)
6666
_ <- IO.println(s"successfully parsed $x and $y")
6767
yield ()
6868
.rescue:
6969
case ParseError.UnclosedBracket => IO.println("you didn't close your brackets")
7070
case ParseError.MissingSemicolon => IO.println("you missed your semicolons very much")
71-
case Other(msg) => IO.println(s"error: $msg")
71+
case ParseError.Other(msg) => IO.println(s"error: $msg")
7272
```
7373

7474
There's a lot to unpack here! At the very beginning we define a custom error type, `ParseError`. This is just a domain error like any other, and you'll note that it *doesn't* extend `Exception` or `Throwable` or similar. Without Cats MTL, we would generally have to wrap this error up in `Either` in all our function's result types, if we wanted to use it (similar to what Circe does). In this case though, instead of adding the error to the result type, we added a `using` parameter to our `parse` function!
@@ -95,8 +95,8 @@ import cats.mtl.{Handle, Raise}
9595
sealed trait ParseError extends Product with Serializable
9696

9797
object ParseError {
98-
case class UnclosedBracket extends ParseError
99-
case class MissingSemicolon extends ParseError
98+
case object UnclosedBracket extends ParseError
99+
case object MissingSemicolon extends ParseError
100100
case class Other(msg: String) extends ParseError
101101
}
102102

@@ -112,7 +112,7 @@ def parse[F[_]](input: String)(implicit r: Raise[F, ParseError], m: Monad[F]): F
112112
}
113113

114114
// use allow/rescue like try/catch to create scoped error handling
115-
val program: IO[Result] = Handle.allowF[IO, ParseError] { implicit h =>
115+
val program: IO[Unit] = Handle.allowF[IO, ParseError] { implicit h =>
116116
for {
117117
x <- parse[IO](inputX)
118118
y <- parse[IO](inputY)
@@ -121,7 +121,7 @@ val program: IO[Result] = Handle.allowF[IO, ParseError] { implicit h =>
121121
} rescue {
122122
case ParseError.UnclosedBracket => IO.println("you didn't close your brackets")
123123
case ParseError.MissingSemicolon => IO.println("you missed your semicolons very much")
124-
case Other(msg) => IO.println(s"error: $msg")
124+
case ParseError.Other(msg) => IO.println(s"error: $msg")
125125
}
126126
```
127127

0 commit comments

Comments
 (0)