Haskell类型注释在函数中 [英] Haskell type annotation in function

查看:131
本文介绍了Haskell类型注释在函数中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Haskell似乎没有认出我的类型注释如下。为什么会这样?



这里的Runner是一个函数的包装器,它的默认起始值​​是c(一个continuant)。在rmap中,我希望c有一个默认的开始值(例如,如果c是[a],我会让该值为[])。这里当然不方便(也许这是不好的做法,随意提出一个更好的方法)是需要类型注释,因为rmap的域不涉及类型c。然而,为什么我不能通过类型注释修复这个问题?

  data ExitCode = Fail |好的|成功派生(Eq,Show)

数据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))
pre>

错误如下。 (它似乎将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# - } 

- 其他声明

rmap :: forall ab c。尖c => (a - > b) - > Runner abc
rmap f = Runner(point :: c)(\(x,y,z) - >(fx,y,z))
pre>

使用 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 。这适用于像 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 use

rmap :: 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 the forall syntax and have a and b declared as well. Again, it isn't necessary for this particular problem, GHC can automatically figure out which instance of Pointed 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) without ScopedTypeVariables, the c in the function definition is a different c in the type signature. This works with concrete types like Int 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 is Test 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆