Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 无法从上下文推断(简单)类型类_Haskell - Fatal编程技术网

Haskell 无法从上下文推断(简单)类型类

Haskell 无法从上下文推断(简单)类型类,haskell,Haskell,我在一个非常简单的例子中遇到了一个错误,我无法找出错误所在。我所做的与Monoid中的mempty非常相似,这里有一个简单的版本(我包括我的量化类型,以防与问题有关): 我得到的错误是: Could not deduce (EsMappable t0) arising from a use of ‘fields’ from the context (EsMappable a) bound by the type signature for toMapping ::

我在一个非常简单的例子中遇到了一个错误,我无法找出错误所在。我所做的与
Monoid
中的
mempty
非常相似,这里有一个简单的版本(我包括我的量化类型,以防与问题有关):

我得到的错误是:

Could not deduce (EsMappable t0) arising from a use of ‘fields’
from the context (EsMappable a)
  bound by the type signature for
             toMapping :: EsMappable a => a -> String
  at search2.hs:11:14-42
The type variable ‘t0’ is ambiguous
In the second argument of ‘go’, namely ‘fields’
In the expression: go "" fields
In an equation for ‘toMapping’:
    toMapping a
      = go "" fields
      where
          go str [] = str
          go str (ReferenceField name _ : xs) = go (name ++ str) xs
          go str (Field name : xs) = go (name ++ str) xs
注意:如果我将
EsMapapble
类更改为:
fields::a->[Field a]
,然后在
映射中更改
go”“(fields a)
,它会起作用

我的问题:为什么我会出现这个错误?这与
mempty
不一样吗?是什么阻止GHC正确解析
字段


谢谢大家!

问题在于编译器无法将
字段的使用与参数
a
链接起来。对于任何
a
,您的
go
函数都可以接受
[字段a]
,因此您需要以某种方式明确地将其约束为与参数类型中的
a
相同

使用
ScopedTypeVariables
可以很好地实现这一点:

toMapping :: forall a. (EsMappable a) => a -> String
toMapping _ = go "" (fields :: [Field a])
您需要为所有a
添加额外的
,以显式地将
a
类型变量范围化。为了向后兼容,这是对
ScopedTypeVariables
的限制

如果将
a
参数与
go
中的
字段a
值一起使用,这也不会是一个问题。作为一个人为的例子,以下类型检查没有明确的签名:

go str (ReferenceField name f : xs) = go (name ++ str) xs `const` f a

这将强制
f
采用类型为
a
的参数,这将整个列表约束为特定的
a
。因此,如果您真的想要,您实际上可以使用这个技巧来避免
ScopedTypeVariables
扩展!不过,我不建议这样做:这个扩展几乎是无害的,并且使代码更加清晰。这个例子只是为了说明我的观点。

谢谢你的快速回答。我现在明白了其中的微妙之处。此外,看到您使用
const
约束
a
的示例非常有帮助,也是一个很好的例子,尽管有点老套,但说明了懒惰是有用的!
go str (ReferenceField name f : xs) = go (name ++ str) xs `const` f a