purescript

How to use instance chain to solve overlapping


I'm having trouble with instance chaining in PureScript version 0.12.0-rc1. The way I understand it, an instance chain allows one to specify instance resolution order explicitly to avoid instance definition overlapping.

I came up with the following example, but it won't compile:

class A a
class B b
class C c where
  c :: c -> String

instance ca :: A a => C a where
  c = const "ca"
else
instance cb :: B b => C b where
  c = const "cb"

data X = X
instance bx :: B X

main :: forall eff. Eff (console :: CONSOLE | eff) Unit
main = logShow $ c X

What did I do wrong? Is my use of instance chaining incorrect?

Here's the full error message:

Error found:
in module Main
at src/Main.purs line 23, column 8 - line 23, column 20

  No type class instance was found for

Main.A X


while applying a function c
  of type C t0 => t0 -> String
  to argument X
while inferring the type of c X
in value declaration main

where t0 is an unknown type

Solution

  • Even with instance chains matching is still done on the head of an instance. There is no "backtracking" when any of constraint fails for the chosen instance.

    Your instances are completely overlapping on the head, so your first instance always matches before second one and it fails because there is no A instance for X.

    Instance chains allows you to define explicit ordering of instance resolution without relying on for example alphabetical ordering of names etc. (as it was done till 0.12.0 version - please check the third paragraph here). For example you can define this overlapping scenario:

    class IsRecord a where
       isRecord :: a -> Boolean
    
    instance a_isRecordRecord :: IsRecord (Record a) where
       isRecord _ = true
    
    instance b_isRecordOther :: IsRecord a where
       isRecord _ = false
    

    as

    instance isRecordRecord :: IsRecord (Record a) where
       isRecord _ = true
    else instance isRecordOther :: IsRecord a where
       isRecord _ = false
    

    I hope it compiles - I don't have purs-0.12.0-rc yet ;-)