[英]Haskell type annotation in function
Haskell似乎没有识别我的类型注释。 为什么是这样?
这里Runner是一个函数的包装器,具有c的默认起始值(“连续”)。 在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))
为了在类似的定义中使用类型变量,您需要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
使用的是什么实例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.