Haskell类型注释在函数中 [英] Haskell type annotation in function
问题描述
这里的Runner是一个函数的包装器,它的默认起始值是c(一个continuant)。在rmap中,我希望c有一个默认的开始值(例如,如果c是[a],我会让该值为[])。这里当然不方便(也许这是不好的做法,随意提出一个更好的方法)是需要类型注释,因为rmap的域不涉及类型c。然而,为什么我不能通过类型注释修复这个问题?
data ExitCode = Fail |好的|成功派生(Eq,Show)
pre>
数据Runner abc = Runner {cont :: c
,fun ::(a,c,ExitCode) - >(b,c,ExitCode) }
class指向一个地方
point :: a
rmap ::(Pointed c)=> (a-> b) - > Runner abc
rmap f = Runner(point :: c)(\(x,y,z) - >(fx,y,z))
错误如下。 (它似乎将c解释为c1)。
无法推断(指向c1)由于使用了点
从上下文(指向c)
绑定到
的类型签名rmap ::指向c => (a - > b) - > Runner abc
在Runner.hs:39:8-44
可能的修正:
add(指向c1)到
的上下文表达式类型签名:c1
或
的类型签名rmap :: Pointed c => (a - > b) - > Runner abc
在Runner的第一个参数中,即`(point :: c)'
在表达式中:Runner(point :: c)(\(x,y,z) - >(fx,y,z))
在'rmap'的等式中:
rmap f = Runner(point :: c)(\(x,y,z) - >( fx,y,z))
解决方案类型变量,你需要
ScopedTypeVariables
语言扩展,但在这种情况下,你根本不需要scoped类型变量,只需使用rmap ::尖c => (a - > b) - > Runner abc
rmap f = Runner point(\(x,y,z) - >(fx,y,z))
如果你确实想要
(point :: c)
,你可以做
{ - #LANGUAGE ScopedTypeVariables# - }
pre>
- 其他声明
rmap :: forall ab c。尖c => (a - > b) - > Runner abc
rmap f = Runner(point :: c)(\(x,y,z) - >(fx,y,z))
使用
ScopedTypeVariables
,您还必须显式使用forall
语法并且同时声明a 和 b
。同样,这个特殊的问题没有必要,GHC可以自动计算出Pointed
使用哪个实例。
<即使使用GHC 7.8,类型签名甚至不需要,它可以自动派生它:
>让rmap f =跑道点(\(x,y,z) - >(f x,y,z))
> :t rmap
rmap :: Pointed c => (a - > b) - > Runner abc
这个错误的起源是当你有
(point :: c)
,没有ScopedTypeVariables
,c $ c $函数定义中的c>在类型签名中是不同的
c
。这适用于像Int
这样的具体类型,因为它们已经在作用域中,但对于类型变量不是这样。
至于为什么它在函数的域中不存在
c
:GHC的类型推断非常聪明。它会让你传递一个通用的值,直到你要求它具体化,然后所有正确的实例被使用。例如,如果我反而有类似于
>数据Test a b c = Test {t :: c,x ::(a,b)}派生(Eq,Show)
>实例指向[Double]其中point = [1,2,3] - 需要FlexibleInstances
>让测试::指出c => a - > b - >测试一个b c
|测试a b =测试点(a,b)
> test 1test:: Test Int String [Double]
Test {t = [1.0,2.0,3.0],x =(1,test)}
虽然
c
不会作为参数出现,但类型检查程序仍有可能当我指定返回类型是Test Int String [Double]
时,找出使用哪个实例。没有指定签名,它反而给了我错误< interactive>:30:1:
没有实例for(指向c0)由于使用'it'而引起
类型变量`c0'不明确
注意:有一个潜在实例可用:
实例指向[Double] - 定义在< interactive>:19:10
在'print'的第一个参数中,也就是'it'
在一个交互式GHCi命令的列表中:print it
,因为它不知道要使用哪个
指向
的实例。Haskell doesn't seem to recognize my type annotation below. Why is this?
Here Runner is a wrapper for a function, with a default starting value for c (a "continuant"). In rmap, I want c to have a default "starting" value (for example, if c were [a] I would let that value be []). What's of course inconvenient here (and perhaps this is bad practice, feel free to suggest a better way) is that a type annotation is required since the domain of rmap does not involve the type c. However, why can I not fix this by a type annotation?
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))
The error is the following. (It seems to be interpreting c as 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))
解决方案In order to use type variables in a definition like that, you need the
ScopedTypeVariables
language extension, but in this case you don't need the scoped type variable at all, just usermap :: Pointed c => (a -> b) -> Runner a b c rmap f = Runner point (\(x, y, z) -> (f x, y, z))
If you really really want to have
(point :: c)
, you can do{-# 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))
With
ScopedTypeVariables
you also have to explicitly use theforall
syntax and havea
andb
declared as well. Again, it isn't necessary for this particular problem, GHC can automatically figure out which instance ofPointed
to use.Even with GHC 7.8, the type signature isn't even required, it can derive it automatically:
> let rmap f = Runner point (\(x, y, z) -> (f x, y, z)) > :t rmap rmap :: Pointed c => (a -> b) -> Runner a b c
The origin of this error is that when you had
(point :: c)
withoutScopedTypeVariables
, thec
in the function definition is a differentc
in the type signature. This works with concrete types likeInt
because they're already in scope, but not so with type variables.
So as to why this works without having
c
in the domain of the function: GHC's type inference is really smart. It'll let you pass around a generic value until the point that you require it to be concrete, then all the right instances get used. For example, if I instead had something like> 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")}
Even though
c
doesn't appear as an argument, it's still possible for the type checker to figure out which instance to use when I've specified that the return type isTest Int String [Double]
. Without specifying the signature, it instead gives me the error<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
because it doesn't know what instance of
Pointed
to use.这篇关于Haskell类型注释在函数中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!