Json 如何使用多个';数据';其中一个为';推导';从类型函数开始?
我正在努力使以下代码正常工作(好吧,首先编译!) 所以我必须启用Json 如何使用多个';数据';其中一个为';推导';从类型函数开始?,json,haskell,serialization,Json,Haskell,Serialization,我正在努力使以下代码正常工作(好吧,首先编译!) 所以我必须启用FlexibleContexts才能执行数据(表示a),但它仍然不起作用 我有一个错误: src/Orexio/Radix.hs:21:33: Could not deduce (Data a0) arising from a use of `query' from the context (Data a, Resource a,
FlexibleContexts
才能执行数据(表示a)
,但它仍然不起作用
我有一个错误:
src/Orexio/Radix.hs:21:33:
Could not deduce (Data a0) arising from a use of `query'
from the context (Data a,
Resource a,
Endpoint a,
Data (Representation a))
bound by the type signature for
bind :: (Data a, Resource a, Endpoint a,
Data (Representation a)) =>
Binding a
at src/Orexio/Radix.hs:20:9-78
The type variable `a0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance Data HelloWorld -- Defined at src/Orexio/Radix.hs:29:29
instance Data () -- Defined in `Data.Data'
instance (Data a, Data b) => Data (a, b) -- Defined in `Data.Data'
...plus 42 others
In the second argument of `($)', namely `query x'
In the expression: binding $ query x
In the first argument of `Binding', namely
`(\ x -> binding $ query x)'
老实说,我有点迷路了,我肯定错过了什么,但是什么
以下是我激活的其他扩展:DeriveDataTypeable
,存在量化
,NoMonomorphismRestriction
,类型族
提前谢谢 看起来
绑定a
应该是一个将a
类型的值转换为表示a
类型的值或错误消息的函数。但是,由于输入和输出都是JSON编码的,因此它们都具有类型JSValue
;他们的类型根本没有提到a
data Binding a = Binding (JSValue -> Either String JSValue)
没有任何信息表明那些JSValue
s代表什么类型
在bind
的定义中,编译器知道返回类型是Binding a
,但该类型与JSValue
s的类型之间没有联系。特别是,编译器无法推断fromJSON
应返回a
,而toJSON
应采用表示法a
。要解决此问题,请将显式类型签名添加到绑定
和查询
有时让人困惑的一个细节是如何告诉GHC类型变量范围。这需要
ScopedTypeVariables
扩展名。将forall a.
添加到bind
的类型签名中,并将forall.
添加到bind
正文中的其他类型签名中,以便变量a
的范围正确。类型错误的本质是这一行:“类型变量'a0'不明确”
(免责声明:我试图在回答中避免使用行话。)
为了理解这里发生了什么,我建议将绑定
和查询
绑定浮动到顶层。如果您随后注释掉bind
binding,他们将成功地进行打字检查。GHC推断出以下类型
*Orexio.Radix> :i query
query :: Data a => JSValue -> Result a
*Orexio.Radix> :i binding
binding ::
(Data (Representation a), Endpoint a, Resource a) =>
Result a -> Either String JSValue
您的错误主要是由bind
定义中的表达式\x->binding(query x)
引起的。请注意,类型变量a
仅出现在binding
域和query
范围内。因此,当你创作它们时,会发生两件事
JSValue->
字符串JSValue
show
-read
问题”;在哈斯克尔的真实世界中搜索“模棱两可”。(有些人也可能称之为“太多多态性”。)
正如您和Sjoerd所确定的(以及RWH章节所解释的),您可以通过在应用绑定之前将类型归因于查询的结果来修复此类型错误。在不了解语义的情况下,我假设您希望此“隐藏”类型变量a
与绑定
类型构造函数的参数相同。因此,下面的方法是可行的
bind :: forall b.
(Data b, Resource b, Endpoint b, Data (Representation b)) => Binding b
bind = Binding (\x -> binding $ (query x :: Result b))
这种归属消除了类型变量a
,将其完全替换为Result b
。请注意,与a
不同,b
保持不确定状态是可以接受的,因为它在顶级类型中是可访问的;使用bind
可以分别确定b
第一种解决方案需要给bind
一个明确的签名,这有时会非常繁重。在本例中,由于单态限制,您可能已经需要该类型签名。但是,如果bind
接受了一个参数(但仍然显示出这个不明确的类型变量错误),您仍然可以通过使用如下解决方案依赖类型推断
dummy_ResultType :: Binding a -> Result a
dummy_ResultType = error "dummy_ResultType"
bind () = result where
result = Binding (\x -> binding $ (query x `asTypeOf` dummy))
dummy = dummy_ResultType result
(如果使用error
会让您担心,请参阅。)
或者用一些习语来换取直截了当:
withArgTypeOf :: f x -> g x -> f x
withArgTypeOf x _ = x
bind () = result where
result = Binding (\x -> binding (query x `withArgTypeOf` result))
现在推理起作用了
*Orexio.Radix> :i bind
bind ::
(Data (Representation a), Data a, Endpoint a, Resource a) =>
() -> Binding a
请放心,GHC会在类型检查后快速确定定义实际上不是递归的
HTH.遵循GHC给您的建议:“可能的修复:添加一个类型签名来修复这些类型变量”@SjoerdVisscher我试图将它们放在不同的位置(在查询RHS和绑定RHS中),但没有成功。你会把它们放在哪里?谢谢你的回答我现在对这个问题有了更好的理解,但在添加类型注释后我仍然在努力,以下是我现在拥有的:但它仍然没有编译:-(@Alois,从绑定和查询中删除孔和约束。使用孔可以创建新的类型变量,但关键是使用bind
签名中的a
。@AloisCochard,还有,您是否打开了ScopedTypeVariables?@SjoerdVisscher awesome让它工作了,我应该读更多关于作用域如何工作的内容!thanks很多:-)
*Orexio.Radix> :i bind
bind ::
(Data (Representation a), Data a, Endpoint a, Resource a) =>
() -> Binding a