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 start value for c ("continued"). In rmap, I want c to have a "start" value by default (for example, if c were [a], I would give this value a []). Which, of course, is inconvenient here (and perhaps this is bad practice, feel free to suggest a better way) is that type annotation is required, since the rmap scope does not include type c. However, why can't I fix this with type annotation?

data ExitCode = Fail | OK | Success deriving (Eq, Show) data Runner abc = Runner {cont ::c , fun :: (a, c , ExitCode) ->(b, c, ExitCode)} class Pointed a where point :: a rmap:: (Pointed c) => (a->b) -> Runner abc rmap f = Runner (point::c) (\(x,y,z) -> (fx,y,z)) 

The following error. (He seems to interpret 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 abc 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 abc In the first argument of `Runner', namely `(point :: c)' In the expression: Runner (point :: c) (\ (x, y, z) -> (fx, y, z)) In an equation for `rmap': rmap f = Runner (point :: c) (\ (x, y, z) -> (fx, y, z)) 
+5
source share
1 answer

To use type variables in such a definition, you need a ScopedTypeVariables language ScopedTypeVariables , but in this case you don't need a scope type variable at all, just use

 rmap :: Pointed c => (a -> b) -> Runner abc rmap f = Runner point (\(x, y, z) -> (fx, y, z)) 

If you really want to have (point :: c) , you can do

 {-# LANGUAGE ScopedTypeVariables #-} -- other declarations rmap :: forall ab c. Pointed c => (a -> b) -> Runner abc rmap f = Runner (point :: c) (\(x, y, z) -> (fx, y, z)) 

With ScopedTypeVariables you also need to explicitly use the forall syntax and declare a and b . Again, this is not necessary for this particular problem, the GHC can automatically determine which instance of Pointed use.

Even with GHC 7.8, a type signature is not even required, it can be automatically output:

 > let rmap f = Runner point (\(x, y, z) -> (fx, y, z)) > :t rmap rmap :: Pointed c => (a -> b) -> Runner abc 

The origin of this error is that if (point :: c) without ScopedTypeVariables , c in the function definition is different from c in the type signature. This works with specific types, such as Int , because they are already in scope, but not so with type variables.


So why does this work without having c in the function domain: GHC type inference is really smart. This will allow you to pass in the general value until you need a specific one, then all the correct instances will be used. For example, if I had something like

 > data Test abc = 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 abc | test ab = Test point (a, b) > test 1 "test" :: Test Int String [Double] Test {t = [1.0,2.0,3.0], x = (1,"test")} 

Although c not displayed as an argument, it is still possible for the type checker to figure out which instance to use when I specified that the return type is Test Int String [Double] . Without specifying a signature, he instead gives me an 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 he does not know which instance of Pointed use.

+9
source

Source: https://habr.com/ru/post/1200615/


All Articles