繁体   English   中英

函数中的Haskell类型注释

[英]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语法并同时声明ab 同样,对于这个特定问题没有必要,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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM