- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试创建另一个 Random 实例,但遇到了类型错误。我将其简化为以下 ghci session :
GHCi, version 8.6.5:
λ> import System.Random
λ> :t random
random :: (Random a, RandomGen g) => g -> (a, g)
λ> :t \g -> random g
\g -> random g :: (Random a, RandomGen g) => g -> (a, g)
λ> :t \g -> let xh = random g in xh
\g -> let xh = random g in xh
:: (Random a, RandomGen g) => g -> (a, g)
λ> :t \g -> let (x, h) = random g in (x, h)
<interactive>:1:11: error:
• Could not deduce (Random a0)
from the context: (Random a, RandomGen b)
bound by the inferred type of
it :: (Random a, RandomGen b) => b -> (a, b)
at <interactive>:1:1
The type variable ‘a0’ is ambiguous
• When checking that the inferred type
h :: forall a. Random a => b
is as general as its inferred signature
h :: b
In the expression: let (x, h) = random g in (x, h)
In the expression: \ g -> let (x, h) = ... in (x, h)
为什么上个版本会失败?
最佳答案
这是一个可爱的问题。您可能会想象这会被翻译成像这样的显式字典传递样式:
-- original
foo = \g -> let (x, h) = random g in (x, h)
-- assumed but incorrect explicit version
foo = /\a. /\b. \\(da :: Random a) => \\(db :: RandomGen b) =>
\(g :: b) -> let tmp = random @a @b ,da ,db g
x = case tmp of (x, h) -> x
h = case tmp of (x, h) -> h
in (x, h)
这里我使用了一些自定义的新语法:
/\ty。 tm
是显式类型抽象;它接受一个类型,将其命名为 ty
,并按照术语 tm
的方式进行tm @ty
是显式类型应用;它采用多态项 tm
并提供 ty
作为第一个类型参数\\(dict::c) => tm
是明确的类型类抽象;它采用作为约束 c
证据的类型类字典,将其命名为 dict
,并像术语 tm
一样继续tm ,dict
是显式类型类应用;它接受一个假定某个类型类实例的术语,并提供字典 dict
作为该实例的证据如果这就是编译的方式,那么就不会有歧义,\g -> let (x, h) = random g in (x, h)
只会与前面所有术语的类型相同。但这并不是模式绑定(bind)的实际编译方式,因为这使得 x
和 h
的类型比它们需要的更具限制性。相反,它是这样编译的:
-- actual explicit version
foo = /\a. /\b. /\c. \\(da :: Random a) => \\(db :: Random b) => \\(dc :: RandomGen c) =>
\(g :: b) -> let x = /\d. \\(dd :: Random d) =>
case random @d @c ,dd ,dc g of (x, h) -> x
h = /\d. \\(dd :: Random d) =>
case random @d @c ,dd ,dc g of (x, h) -> h
in (x @a ,da , h @b ,db)
这个是更多态,因为在计算 x
时用于选择 Random
实例的类型与用于选择的类型无关在计算 h
时选择一个 Random
实例。在这种情况下,这不是您想要的;但是可以设想其他情况,这正是您想要的,并且将这两种类型捆绑在一起对于表达您想要的计算非常不方便。
但是,由于这种翻译允许额外的灵 active ,我们发现自己在这里有点困难:这个东西的调用者如何影响为 b
选择的类型并不那么明显(因此 db
使用哪个字典),因为 b
没有出现在整个类型的任何地方!所以编译器给你一个类型歧义错误。作为一个直观的解释:我们知道要使用哪个 Random
实例来计算 x
,因为调用者必须为元组的第一部分选择一个类型;但是我们不知道要使用哪个实例来计算 h
,因为为 h
选择类型并不能确定要为丢弃的 x< 使用什么类型
计算的一半用于定义 h
。
您可以通过启用 MonoLocalBinds
扩展要求编译器选择第一个翻译。您可以阅读更多相关信息 here .它有时会阻止 let
绑定(bind)以上述方式变为多态,这意味着类型推断将有更多线索,但一些其他可接受的程序将不再进行类型检查。
关于 haskell 错误 : Could not deduce (Random a0),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60493352/
我是一名优秀的程序员,十分优秀!