- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
所以让我们假设你有两个这样定义的类型类:
{-# LANGUAGE MultiParamTypeClasses #-}
class F a c where f :: a -> c
class G c b where g :: c -> b
然后您想使用 f 和 g 以通用方式定义一个新函数 h。
h a = g (f a)
我们知道这个函数的类型是 a -> b
所以 c 是隐式的。我想把 f
和 g
的实现者留给 c
可能是什么。 Haskell 提示说 c
是模棱两可的。
然后按照错误的提示我打开了这个扩展:
{-# LANGUAGE AllowAmbiguousTypes #-}
现在可以了!不错。
我相信通常作为一种良好的软件工程实践,我想为我的函数编写明确的规范,以告诉编译器我期望我的函数应该有什么样的行为。这样以后的编译器就可以提示我不遵守我的设置。
所以我想在它之前添加我的函数的类型:
h :: (F a c, G c b) => a -> b
h a = g (f a)
现在类型歧义错误又来了...为什么?
总结一下为什么 Haskell 会提示下面这段代码? 即使显式启用了 AllowAmbiguousTypes。如何在保持显式函数类型定义的同时修复它?我知道删除函数的类型定义可以解决问题,但我不想指定不足。
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
class F a c where f :: a -> c
class G c b where g :: c -> b
h :: (F a c, G c b) => a -> b
h a = g (f a)
为什么 Haskell 不提示这个?
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
class F a c where f :: a -> c
class G c b where g :: c -> b
h a = g (f a)
错误信息:
error:
* Could not deduce (G c0 b) arising from a use of `g'
from the context: (F a c, G c b)
bound by the type signature for:
h :: forall a c b. (F a c, G c b) => a -> b
The type variable `c0' is ambiguous
Relevant bindings include
h :: a -> b
* In the expression: g (f a)
In an equation for `h': h a = g (f a)
|
| h a = g (f a)
| ^^^^^^^
error:
* Could not deduce (F a c0) arising from a use of `f'
from the context: (F a c, G c b)
bound by the type signature for:
h :: forall a c b. (F a c, G c b) => a -> b
The type variable `c0' is ambiguous
Relevant bindings include
a :: a
h :: a -> b
* In the first argument of `g', namely `(f a)'
In the expression: g (f a)
In an equation for `h': h a = g (f a)
|
| h a = g (f a)
| ^^^
最佳答案
您的代码含糊不清,编译器无法自动解决。假设这样:
class F a c where f :: a -> c
class G c b where g :: c -> b
instance F Int String where f = show
instance G String Bool where g = null
h :: (F Int c, G c Bool) => Int -> Bool
h a = g (f a)
现在,最后一行使用了哪些实例?我们有两个选择:使用上下文 (F Int c, G c Bool)
提供的实例,或者忽略该上下文并使用上面的实例,以 String
作为中间类型。两种解释都是正确的,我们确实可以明确地写
h1 :: forall c. (F Int c, G c Bool) => Int -> Bool
h1 a = (g :: c -> Bool) (f a)
h2 :: forall c. (F Int c, G c Bool) => Int -> Bool
h2 a = (g :: String -> Bool) (f a)
选择一种方式或另一种方式。 GHC无法以合理的方式为我们做这个选择。它可以根据一些试探法选择一个,但这会给程序员带来很多惊喜。因此,我们可以争辩说 GHC 绝对不能选择,报告歧义,并让程序员阐明他们的意图。
最后,请注意,您的代码不包含上述两个实例这一事实是无关紧要的,因为它们可以稍后添加,甚至可以添加到另一个模块中,因此 GHC 必须保守并避免假设它们永远不存在。
And why doesn't Haskell complain about this?
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
class F a c where f :: a -> c
class G c b where g :: c -> b
h x = g (f x) -- [renamed to x for clarity]
好点。这里GHC可以找到一个最通用的类型,就是
h :: forall a b c. (F a c, G c b) => a -> b
h x = (g :: c -> b) ((f :: a -> b) x)
由于这里是GHC加入了类型变量c
,GHC可以确定这个类型就是中间类型。毕竟,该类型变量是在类型推断期间创建的,用于表示中间类型。
相反,当用户显式写入上下文时,GHC 无法猜测用户的意图。有可能,即使在实践中不太可能,用户不想使用该实例,而是另一个实例(在程序中可用,但不存在于上下文中)。
考虑一下这个案例也可能会有所帮助:
data T = ....
h :: forall a b c. (F a c, G c b, F a T, G T b) => a -> b
h x = g (f x)
我认为您同意应该拒绝此代码:中间类型可能是 T
或 c
,并且没有解决它的明智方法。现在考虑这种情况:
h :: forall a b c. (F a c, G c b) => a -> b
h x = g (f x)
instance F a T where ...
instance G T b where ...
现在,这与之前的情况并没有太大不同。我们没有在上下文中有两个选项,而是将一个选项移到了外面。不过,GHC 仍然有两个选项可供选择。所以,再一次,明智的做法是拒绝代码,并向程序员询问更多细节。
一个更简单的场景,在 GHCi 中:
> :set -XScopedTypeVariables
> :set -XAllowAmbiguousTypes
> class C a where c :: String
> instance C Int where c = "Int"
> instance C Bool where c = "Bool"
> let g :: forall a. C a => String ; g = c
<interactive>:7:40: error:
* Could not deduce (C a0) arising from a use of `c'
在这里,GHC 怎么知道当我写 g = c
时,我的意思是“c
来自上下文 C a
?我可以写出意思是“Int
实例中的 c
”。或者 Bool
。
GHC 在内部生成一个新的类型变量 a0
,然后尝试解决约束 C a0
。它具有三个选择:选择 a0 = a
、a0 = Int
或 a0 = Bool
。 (以后可以添加更多实例!)
所以,它是模棱两可的,如果不猜测程序员的意图,就没有理智的方法来修复它。唯一安全的选择是拒绝。
关于haskell - 在 Haskell 中,为什么即使启用了 AllowAmbiguousTypes 类型也会有歧义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58471799/
我正在尝试编写一个相当多态的库。我遇到了一种更容易表现出来却很难说出来的情况。它看起来有点像这样: {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE
谁能解释一下这个表达式是如何工作的? type = type || 'any'; 这是否意味着如果类型未定义则使用“任意”? 最佳答案 如果 type 为“falsy”(即 false,或 undef
我有一个界面,在IAnimal.fs中, namespace Kingdom type IAnimal = abstract member Eat : Food -> unit 以及另一个成功
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: What is the difference between (type)value and type(va
在 C# 中,default(Nullable) 之间有区别吗? (或 default(long?) )和 default(long) ? Long只是一个例子,它可以是任何其他struct类型。 最
假设我有一个案例类: case class Foo(num: Int, str: String, bool: Boolean) 现在我还有一个简单的包装器: sealed trait Wrapper[
这个问题在这里已经有了答案: Create C# delegate type with ref parameter at runtime (1 个回答) 关闭 2 年前。 为了即时创建委托(dele
我正在尝试获取图像的 dct。一开始我遇到了错误 The function/feature is not implemented (Odd-size DCT's are not implemented
我正在尝试使用 AFNetworking 的 AFPropertyListRequestOperation,但是当我尝试下载它时,出现错误 预期的内容类型{( “应用程序/x-plist” )}, 得
我在下面收到错误。我知道这段代码的意思,但我不知道界面应该是什么样子: Element implicitly has an 'any' type because index expression is
我尝试将 SignalType 从 ReactiveCocoa 扩展为自定义 ErrorType,代码如下所示 enum MyError: ErrorType { // .. cases }
我无法在任何其他问题中找到答案。假设我有一个抽象父类(super class) Abstract0,它有两个子类 Concrete1 和 Concrete1。我希望能够在 Abstract0 中定义类
我想知道为什么这个索引没有用在 RANGE 类型中,而是用在 INDEX 中: 索引: CREATE INDEX myindex ON orders(order_date); 查询: EXPLAIN
我正在使用 RxJava,现在我尝试通过提供 lambda 来订阅可观察对象: observableProvider.stringForKey(CURRENT_DELETED_ID) .sub
我已经尝试了几乎所有解决问题的方法,其中包括。为 提供类型使用app.use(express.static('public'))还有更多,但我似乎无法为此找到解决方案。 index.js : imp
以下哪个 CSS 选择器更快? input[type="submit"] { /* styles */ } 或 [type="submit"] { /* styles */ } 只是好
我不知道这个设置有什么问题,我在 IDEA 中获得了所有注释(@Controller、@Repository、@Service),它在行号左侧显示 bean,然后转到该 bean。 这是错误: 14-
我听从了建议 registering java function as a callback in C function并且可以使用“简单”类型(例如整数和字符串)进行回调,例如: jstring j
有一些 java 类,加载到 Oracle 数据库(版本 11g)和 pl/sql 函数包装器: create or replace function getDataFromJava( in_uLis
我已经从 David Walsh 的 css 动画回调中获取代码并将其修改为 TypeScript。但是,我收到一个错误,我不知道为什么: interface IBrowserPrefix { [
我是一名优秀的程序员,十分优秀!