# Domain errors with HasCallStack

**URL:** <https://discourse.haskell.org/t/domain-errors-with-hascallstack/10983>\
**Category:** Uncategorized\
**Created:** [December 9, 2024, 8:48am UTC](https://discourse.haskell.org/t/domain-errors-with-hascallstack/10983 "2024-12-09T08:48:14Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![tomjaguarpaw](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/tomjaguarpaw/32/1230_2.png) [@tomjaguarpaw](https://discourse.haskell.org/u/tomjaguarpaw)\
**Post date:** [December 9, 2024, 8:48am UTC](https://discourse.haskell.org/t/domain-errors-with-hascallstack/10983/1 "2024-12-09T08:48:14Z")

</div>

Here’s my latest article, about how to use `HasCallStack` for error messages in embedded domain specific languages.

- [Domain errors with `HasCallStack`](https://h2.jaguarpaw.co.uk/posts/hascallstack-domain-errors/)

---

<div class="post-metadata">

**Author:** ![BurningWitness](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/burningwitness/32/3665_2.png) [@BurningWitness](https://discourse.haskell.org/u/BurningWitness)\
**Post date:** [December 9, 2024, 10:21am UTC](https://discourse.haskell.org/t/domain-errors-with-hascallstack/10983/2 "2024-12-09T10:21:27Z")

</div>

This feels unnatural.

The `constant` function should have a “position” argument, and for this particular case the position is `getCallstack`. Exceptions are not needed here at all (though I could go as far as to say they’re not needed ever when dealing with expected errors, but that’s just my view on things).

Also I would expect the size check on `Data` to be performed in a separate stage instead of being mushed together with all other future errors.

---

<div class="post-metadata">

**Author:** ![tomjaguarpaw](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/tomjaguarpaw/32/1230_2.png) [@tomjaguarpaw](https://discourse.haskell.org/u/tomjaguarpaw)\
**Post date:** [December 9, 2024, 10:27am UTC](https://discourse.haskell.org/t/domain-errors-with-hascallstack/10983/3 "2024-12-09T10:27:31Z")

</div>

Sure, all those suggestions are fine. This is just a small sketch to present the idea of even carrying around `CallStack`s at all in EDSLs.

---

<div class="post-metadata">

**Author:** ![sgraf](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/sgraf/32/392_2.png) [@sgraf](https://discourse.haskell.org/u/sgraf)\
**Post date:** [December 10, 2024, 9:08am UTC](https://discourse.haskell.org/t/domain-errors-with-hascallstack/10983/4 "2024-12-10T09:08:57Z")

</div>

Quite a nice use case for cheap error locations! Works well for shallow embeddings.

Note that using `error` to throw an exception is not a particularly safe thing to do, because GHC’s optimisations are free to mask it with another _imprecise_ error or a loop.

The latter version where you do `throw` should fare much better, because anything thrown through `raiseIO#` is considered a _precise_ exception and will inhibit strictness analysis, for example.

What’s more, I think I would prefer it if errors where part of `Assembly`, i.e.

```haskell
data Error = ...

data Assembly a
  = MkAssembly (forall es. Stream Constant es -> Stream Error es -> Eff es a)

```

and then you yield errors in `constant` or elsewhere. This has the advantage that you do not _always_ need to capture the call stack, which might be expensive (if only in terms of memory residency).

Furthermore, I think it’s likely that one would want to differentiate between fatal errors (which halt the assembly pipeline immediately) and resumable errors (such as your “Wrong size constant”). Resumable errors can be yielded, but fatal errors would need to throw.

---

<div class="post-metadata">

**Author:** ![tomjaguarpaw](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/tomjaguarpaw/32/1230_2.png) [@tomjaguarpaw](https://discourse.haskell.org/u/tomjaguarpaw)\
**Post date:** [December 10, 2024, 12:08pm UTC](https://discourse.haskell.org/t/domain-errors-with-hascallstack/10983/5 "2024-12-10T12:08:14Z")

</div>

Yeah, agreed that imprecise exceptions are not the correct approach. To clarify for those less familiar with the area, “not particularly safe” here doesn’t mean unsafe like `unsafeCoerce` or `unsafePerformIO`, but it does mean it can be uncertain which exception is raised within pure code, for example `error "foo" + error "bar"` is not guaranteed to throw one or the other.

---

<div class="post-metadata">

**Author:** ![danidiaz](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/danidiaz/32/92_2.png) [@danidiaz](https://discourse.haskell.org/u/danidiaz)\
**Post date:** [December 28, 2024, 9:06am UTC](https://discourse.haskell.org/t/domain-errors-with-hascallstack/10983/6 "2024-12-28T09:06:52Z")

</div>

I’ve adopted this technique in the [latest version](https://hackage.haskell.org/package/cauldron-0.6.0.0) of my [cauldron](https://github.com/danidiaz/cauldron/tree/cauldron_0.6.0.0) dependency injection library.

One problem with the previous version was that, because wiring was checked at runtime, I didn’t have the source locations for wiring errors like I would have if wiring were stately checked by the compiler. It would print that a dependency required by the `Bar` constructor was missing, but not point to the source location of `Bar`.

Now, after [storing the `CallStack`s](https://hackage.haskell.org/package/cauldron-0.6.0.0/docs/Cauldron.html#v:val), I can give [nicer errors](https://github.com/danidiaz/cauldron/blob/main/pretty-error-examples.md) like

```haskell
This constructor for a value of type G:
        CallStack (from HasCallStack):
          val, called at app/Main.hs:201:26 in cauldron-0.4.0.0-inplace-cauldron-example-wiring:Main
is missing the following dependencies:
- E

```

I’ve also learned how the function [`withFrozenCallStack`](https://hackage.haskell.org/package/base-4.21.0.0/docs/GHC-Stack.html#v:withFrozenCallStack) might be [useful](https://github.com/danidiaz/cauldron/blob/2f9ed82f68e6439afb5f7c0ea8a7897428aff7ec/lib/Cauldron.hs#L1040): for the purpose of showing error locations, you want to store the `CallStack` only up to when it “enters” the library code, but not accumulate frames for internal calls within your library, which are irrelevant to the user. So in these cases it’s better to freeze the call stack. For example, if I remove a `withFrozenCallStack` [in one of the functions](https://github.com/danidiaz/cauldron/blob/2f9ed82f68e6439afb5f7c0ea8a7897428aff7ec/lib/Cauldron.hs#L1040) and trigger an error, I get:

```haskell
This constructor for a value of type G: CallStack (from HasCallStack):
          val', called at lib/Cauldron.hs:1040:9 in cauldron-0.6.0.0-inplace:Cauldron
          val, called at app/Main.hs:204:18 in cauldron-0.6.0.0-inplace-cauldron-example-wiring:Main
is missing the following dependencies:
- Foo

```

where the line

```haskell
          val', called at lib/Cauldron.hs:1040:9 in cauldron-0.6.0.0-inplace:Cauldron

```

is an internal call within the library and therefore noise.
