简体   繁体   中英

Haskell type annotation in function

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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