为何PureScript无法推断Row.Cons约束?新类型使用疑惑
PureScript新类型约束推断失败问题
代码背景
首先定义了一个带参数化类型的新类型:
newtype MockState m = MockState { apiState :: {api1 :: m Int, api2:: m String} } derive instance newtypeMockState :: Newtype (MockState m) _
随后编写了从字段创建Ref的函数版本1:
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
这个版本编译报错,提示找不到Row.Cons实例:
No type class instance was found for
Prim.Row.Cons s4 (Identity a5) t2 ( cla :: Identity String , login :: Identity Int )
直接传入Record r而非新类型时编译正常,且以下版本可以正常工作:
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
问题原因
两个版本逻辑看似一致,但第一个版本编译失败的核心是编译器缺少足够的类型推断线索:
- 第一个版本直接把约束绑定到具体的
MockState Identity类型上,但Newtype (MockState Identity) {apiState :: Record r}这个约束没有明确建立起MockState Identity内部字段结构和Record r的关联。编译器无法自动将MockState定义里的{api1 :: Identity Int, api2 :: Identity String}和约束中的Record r划等号,自然找不到对应的Row.Cons实例。 - 第二个版本使用泛型的
mock类型变量,再通过unwrap显式提取新类型的内部值,相当于给编译器明确了关联路径:从mock中unwrap得到的结构,其apiState就是Record r,这样编译器能顺利将行类型与Row.Cons约束匹配,完成类型推断。
内容的提问来源于stack exchange,提问作者Saravanan
相关产品推荐
相关产品推荐

