I have a newtype which takes a parameterized type,
newtype MockState m = MockState { apiState :: {api1 :: m Int, api2:: m String} }
derive instance newtypeMockState :: Newtype (MockState m) _
I have a function that creates a ref out of some field,
createRef :: forall s a b r r' rem
. IsSymbol s
=> Newtype (MockState Identity) {apiState :: Record r}
=> Row.Cons s (Identity a) r' r
=> Proxy s
-> MockState Identity
-> Effect (Ref.Ref a)
createRef pxy (MockState mockState)= do
let (Identity val) = Record.get pxy mockState.apiState
Ref.new val
Why the compiler can't resolve the constraint?
No type class instance was found for
Prim.Row.Cons s4
(Identity a5)
t2
( cla :: Identity String
, login :: Identity Int
)
When I pass Record r
directly insted of my newtype, it compiles without any issue... and the below also works..
createRef :: forall s a b mock r' r rem
. IsSymbol s
=> Newtype mock {apiState :: Record r}
=> Row.Cons s (Identity a) r' r
=> Proxy s
-> mock
-> Effect (Ref.Ref a)
createRef pxy r = do
let (Identity val) = Record.get pxy (unwrap r).apiState
Ref.new val
but how? Literally the first one and last are same right? Why the compiler can't infer r
?
This is because the compiler can't see a connection between your Newtype
constraint and the pattern (MockState mockState)
. These are technically unrelated. The Newtype
class is not magic enough for this.
So mockState
is inferred to be of type { apiState :: Record r1 }
, where r1
is distinct from r
, and therefore constraint Cons s (Identity a) r' r
does not apply to r1
.
In order to get the right type inference, you have to unwrap your newtype by utilizing the Newtype
constraint itself. Then the unwrapped value will have type { apiState :: Record r }
, and the Cons
constraint will apply.
You can do this by using the unwrap
function:
createRef pxy mockState= do
let (Identity val) = Record.get pxy (unwrap mockState).apiState
Ref.new val