Haskell似乎无法识别下面的类型注释。这是为什么?
Here Runner是函数的包装器,具有c的默认起始值(a" continuant")。在rmap中,我希望c有一个默认的"开始"值(例如,如果c是[a],我会让该值为[])。这里当然不方便(也许这是不好的做法,随意提出更好的方法)是需要类型注释,因为rmap的域不涉及类型c。但是,为什么我不能通过类型注释来解决这个问题呢?
data ExitCode = Fail | OK | Success deriving (Eq, Show)
data Runner a b c = Runner {cont ::c
, fun :: (a, c , ExitCode) ->(b, c, ExitCode)}
class Pointed a where
point :: a
rmap:: (Pointed c) => (a->b) -> Runner a b c
rmap f = Runner (point::c) (\(x,y,z) -> (f x,y,z))
错误如下。 (似乎将c解释为c1。)
Could not deduce (Pointed c1) arising from a use of `point'
from the context (Pointed c)
bound by the type signature for
rmap :: Pointed c => (a -> b) -> Runner a b c
at Runner.hs:39:8-44
Possible fix:
add (Pointed c1) to the context of
an expression type signature: c1
or the type signature for
rmap :: Pointed c => (a -> b) -> Runner a b c
In the first argument of `Runner', namely `(point :: c)'
In the expression: Runner (point :: c) (\ (x, y, z) -> (f x, y, z))
In an equation for `rmap':
rmap f = Runner (point :: c) (\ (x, y, z) -> (f x, y, z))
答案 0 :(得分:9)
为了在类似的定义中使用类型变量,您需要ScopedTypeVariables
语言扩展,但在这种情况下,您根本不需要范围类型变量,只需使用
rmap :: Pointed c => (a -> b) -> Runner a b c
rmap f = Runner point (\(x, y, z) -> (f x, y, z))
如果你真的想拥有(point :: c)
,你可以做到
{-# LANGUAGE ScopedTypeVariables #-}
-- other declarations
rmap :: forall a b c. Pointed c => (a -> b) -> Runner a b c
rmap f = Runner (point :: c) (\(x, y, z) -> (f x, y, z))
使用ScopedTypeVariables
,您还必须明确使用forall
语法并同时声明a
和b
。同样,对于这个特定问题,它不是必需的,GHC可以自动确定要使用的Pointed
实例。
即使使用GHC 7.8,类型签名也不是必需的,它可以自动导出:
> let rmap f = Runner point (\(x, y, z) -> (f x, y, z))
> :t rmap
rmap :: Pointed c => (a -> b) -> Runner a b c
此错误的来源是,当您(point :: c)
没有ScopedTypeVariables
时,函数定义中的c
在类型签名中是不同的c
。这适用于Int
等具体类型,因为它们已经在范围内,但对于类型变量则不然。
为什么在函数域中没有c
的情况下工作原理:GHC的类型推断非常聪明。它允许您传递一个通用值,直到您要求它具体化,然后使用所有正确的实例。例如,如果我改为喜欢
> data Test a b c = Test { t :: c, x :: (a, b) } deriving (Eq, Show)
> instance Pointed [Double] where point = [1, 2, 3] -- Requires FlexibleInstances
> let test :: Pointed c => a -> b -> Test a b c
| test a b = Test point (a, b)
> test 1 "test" :: Test Int String [Double]
Test {t = [1.0,2.0,3.0], x = (1,"test")}
即使c
没有作为参数出现,但是当我指定返回类型为时,类型检查器仍然可以确定要使用的实例Test Int String [Double]
。没有指定签名,它反而给我错误
<interactive>:30:1:
No instance for (Pointed c0) arising from a use of `it'
The type variable `c0' is ambiguous
Note: there is a potential instance available:
instance Pointed [Double] -- Defined at <interactive>:19:10
In the first argument of `print', namely `it'
In a stmt of an interactive GHCi command: print it
因为它不知道要使用的Pointed
的实例。