在Haskell中,我可以定义一个这样的函数:
foo :: Int -> Int
foo n = n + 1
Run Code Online (Sandbox Code Playgroud)
如果我想成为肛门,我可以在最后一行添加类型签名,如下所示:
foo :: Int -> Int
foo n = n + 1 :: Int
Run Code Online (Sandbox Code Playgroud)
我也可以用bar这样的类型类定义一个函数:
class Rel a b where
aToB :: a -> b
bar :: (Rel a b) => a -> b
bar a = aToB a
Run Code Online (Sandbox Code Playgroud)
但是,如果我在执行中添加类型签名bar(良性更改,或者我认为),我会收到编译错误.
bar :: (Rel a b) => a -> b
bar a = aToB a :: b
Run Code Online (Sandbox Code Playgroud)
这是错误:
Could not deduce (Rel a b1) arising from a use of `aToB'
from the context (Rel a b)
bound by the type signature for bar :: Rel a b => a -> b
at q.hs:79:1-23
Possible fix:
add (Rel a b1) to the context of
an expression type signature: b1
or the type signature for bar :: Rel a b => a -> b
In the expression: aToB val :: b
In an equation for `bar': bar val = aToB val :: b
Run Code Online (Sandbox Code Playgroud)
我认为错误意味着,编译器是不是相信,b在执行bar相同的b在类型签名bar.但是,我不确定为什么会这样.
当我向函数实现添加类型签名时,为什么会出现此编译错误?
您实际上需要语言扩展和一些额外的语法来使两个b类型变量相同:
{-# LANGUAGE ScopedTypeVariables #-}
bar :: forall a b . (Rel a b) => a -> b
bar a = aToB a :: b
Run Code Online (Sandbox Code Playgroud)
在forall本质上说:" a和b在范围上应为全高清",并且ScopedTypeVariables是需要被允许使用此语法.
我想这在语言设计中确实是一个历史性的瑕疵.
您的问题是类型变量的范围。当你写的时候
bar :: (Rel a b) => a -> b
bar a = aToB a :: b
Run Code Online (Sandbox Code Playgroud)
第一行( 的类型声明bar)有自己的类型变量作用域,第二行将 视为与:: b不同的 b Rel a b。
如果您启用ScopedTypeVariables扩展并将您的类型声明为
bar :: forall a b. (Rel a b) => a -> b
Run Code Online (Sandbox Code Playgroud)
那么b的范围就扩展到了 的定义bar。
| 归档时间: |
|
| 查看次数: |
180 次 |
| 最近记录: |