Skip to content

Commit 20bcfc2

Browse files
authored
Merge pull request #367 from kl0tl/add-possibly-infinite-coercible-instance-error
Document `PossiblyInfiniteCoercibleInstance`
2 parents 84e989d + a88f82c commit 20bcfc2

File tree

1 file changed

+46
-0
lines changed

1 file changed

+46
-0
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# `PossiblyInfiniteCoercibleInstance` Error
2+
3+
## Example
4+
5+
```purescript
6+
module ShortFailingExample where
7+
8+
import Safe.Coerce (class Coercible, coerce)
9+
10+
newtype N a = N (a -> N a)
11+
12+
infinite :: forall a b. Coercible a b => N a -> N b
13+
infinite = coerce
14+
```
15+
16+
## Cause
17+
18+
Solving diverges for recursive newtypes: here, the previous example yields the wanted `Coercible (N a) (N b)` which we unwrap on both sides to yield `Coercible (a -> N a) (b -> N b)` and then decompose back to `Coercible a b` and `Coercible (N a) (N b)`.
19+
20+
## Fix
21+
22+
We cannot unwrap newtypes constructors unless they're in scope, so moving the newtype declaration to a separate module and importing only its type prevents the loop.
23+
24+
```diff
25+
+module N where
26+
+
27+
+newtype N a = N (a -> N a)
28+
```
29+
30+
```diff
31+
+import N (N)
32+
-newtype N a = N (a -> N a)
33+
```
34+
35+
## Notes
36+
37+
Note the intervening `->` constructor in the declaration of the newtype. This is actually the issue here because we only unwrap _finite_ chains of newtypes.
38+
39+
For instance given the following declaration:
40+
41+
```purescript
42+
newtype N a = N (N a)
43+
type role N representational
44+
```
45+
46+
When solving a wanted `Coercible (N a) (N b)` we don't unwrap but instead decompose the wanted to `Coercible a b`, which can then eventually be discharged by the context.

0 commit comments

Comments
 (0)