haskell -- can one access type variables from an instance function declaration? - haskell

I want to access type variables in an instance, that don't show up in the instance's parameters. For example,
class A a where foo :: a b
data C a
instance A C where
foo :: forall b. C b
foo = undefined :: C b
Of course, the above will resolve without the scoped type expression, but I have a non-toy example where I actually want it.
edit
please try your code before pasting it as an answer! The above (Daniel's answer) results in
Test.hs:51:5: Misplaced type signature: foo :: forall b. C b
Failed, modules loaded: none.

I think to overcome the problem with Daniel's solution that you are not allowed to provide a signature for a type class function you can simply define a top-level function and "rename" it in the instance of the type class. In your simple example the following should work.
{-# LANGUAGE ScopedTypeVariables #-}
class A a where
foo :: a b
instance A C where
foo = foo'
foo' :: C b
foo' = undefined :: C b

While a real solution would be preferable, one can work around the problem using asTypeOf, and adding dummy parameters. Here's an example,
class A a where foo2 :: b -> a b -- added parameter b
data C a
instance A C where
foo2 x = undefined `asTypeOf` (wrapA x)
wrapA :: A C => a -> C a
wrapA = undefined
foo :: A a => a b
foo = foo2 undefined
That happened to work for my real-world example. cheers!

I think in the class declaration
class A a where
foo :: a b
the type of foo is really
forall b. a b
ie foo should be sort of independent of the type b. Or, b is not actually part of the class A. So... I don't think you should need to be able to refer to it? Though I might not be understanding... maybe you could post an example where it is necessary?
If you need to keep the same type across more than one method you could use a multi-parameter type class:
class A a b where
foo :: a b
bar :: a b

{-# LANGUAGE ScopedTypeVariables #-}
class A a where foo :: a b
instance A C where
foo :: forall b. C b
foo = undefined :: C b
Read more.

Related

Reify existential instance type parameter

I've got some code like this:
{-# LANGUAGE AllowAmbiguousTypes #-}
module Foo where
import Data.Proxy
class Foo x y
class Bar x y
class Baz x y
where
baz :: Proxy x -> Proxy y -> ()
instance (Foo a v, Bar b v) => Baz a b
where
baz _ _ = ()
instance Foo String String
instance Bar Int String
Now I actually want to use that Baz instance, so I write:
test :: Proxy String -> Proxy Int -> ()
test = baz
But of course there is an ambiguous "existential" v type parameter that I have not yet fixed to String (and there's no fundeps), so I get:
[typecheck] [E] /tmp/foo/src/Main.hs:20:8: error:
• Ambiguous type variable ‘v1’ arising from a use of ‘baz’
prevents the constraint ‘(Foo [Char] v1)’ from being solved.
Probable fix: use a type annotation to specify what ‘k1’,
‘v1’ should be.
These potential instance exist:
one instance involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In the expression: baz
In an equation for ‘test’: test = baz
But how can I actually fix that type variable? I can't see a way to fix it using visible type application, because for example the following doesn't work:
test2 :: Proxy String -> Proxy Int -> ()
test2 = baz #String #Int #String -- is there some variation of this that would work?
I also can't see a way to use an explicit type annotation to fix that type parameter. Have I written an instance that is impossible to actually use?
It is indeed impossible to use that instance. When you call baz, you can supply a and b, but not v. v would have to be determined by some combination of superclass and instance constraints, and it is not.
You should be able to patch this up various places. Try either
instance s ~ String => Foo String s
or
instance s ~ String => Bar Int s
for example.

MultiParamTypeClasses - Why is this type variable ambiguous?

Suppose I define a multi-parameter type class:
{-# LANGUAGE MultiParamTypeClasses, AllowAmbiguousTypes, FlexibleContexts, FlexibleInstances #-}
class Table a b c where
decrement :: a -> a
evalutate :: a -> b -> c
Then I define a function that uses decrement, for simplicity:
d = decrement
When I try to load this in ghci (version 8.6.3):
• Could not deduce (Table a b0 c0)
arising from a use of ‘decrement’
from the context: Table a b c
bound by the type signature for:
d :: forall a b c. Table a b c => a -> a
at Thing.hs:13:1-28
The type variables ‘b0’, ‘c0’ are ambiguous
Relevant bindings include d :: a -> a (bound at Thing.hs:14:1)
These potential instance exist:
instance Table (DummyTable a b) a b
This is confusing to me because the type of d is exactly the type of decrement, which is denoted in the class declaration.
I thought of the following workaround:
data Table a b = Table (a -> b) ((Table a b) -> (Table a b))
But this seems notationally inconvenient, and I also just wanted to know why I was getting this error message in the first place.
The problem is that, since decrement only requires the a type, there is no way to figure out which types b and c should be, even at the point where the function is called (thus solving the polymorphism into a specific type) - therefore, GHC would be unable to decide which instance to use.
For example: let's suppose you have two instances of Table: Table Int String Bool, and Table Int Bool Float; you call your function d in a context where it is supposed to map an Int to another Int - problem is, that matches both instances! (a is Int for both).
Notice how, if you make your function equal to evalutate:
d = evalutate
then the compiler accepts it. This is because, since evalutate depends on the three type parameters a, b, and c, the context at the call site would allow for non-ambiguous instance resolution - just check which are the types for a, b, and c at the place where it is called.
This is, of course, not usually a problem for single-parameter type classes - only one type to resolve; it is when we deal with multiple parameters that things get complicated...
One common solution is to use functional dependencies - make b and c depend on a:
class Table a b c | a -> b c where
decrement :: a -> a
evalutate :: a -> b -> c
This tells the compiler that, for every instance of Table for a given type a, there will be one, and only one, instance (b and c will be uniquely determined by a); so it will know that there won't be any ambiguities and accept your d = decrement happily.

Haskell defined types

Studying Haskell first principles. Absolute beginner in Haskell.
If:
data A
data B
func :: A -> B
func = undefined
What would the actual function be? Worked though load of exercises with great result (also thanks to you) but again I am stuck. Does A -> B indicate two different types like 'String' -> 'Char'? Just trying to wrap my head around it.
No, (concrete) types start with an Uppercase. So A -> B means the types A and B you have defined (well not defined here) with your data A = ... expressions, like for instance:
data A = Foo | Bar Int | Qux String A
In case the signature contains an identifier with a lowercase, it is a type variable. For instance foo :: a -> b, means a and b can be substuted by any type. So foo is a function that can be A -> B, but also A -> Int, Char -> B, and Char -> Int.
You can also add type constraints to the signature to restrict the types for which for instance a and b can be used. Like foo :: (Show a, Num b) => a -> b restricts a and b, such that there should exist an instance Show a and instance Num b for the types a and b such that foo is defined over these types.
Thanks Willem, Chepner. Your answers helped me out to conjure up:
data A
data B
funcAJ :: A -> B
funcAJ a = a
where a = b
b = undefined
This typechecks as funcAJ :: A -> B, which I understand. Thanks so much!

MultiParamTypeClasses, FunctionalDependencies, and calling ambiguous functions

With functional dependencies, I can declare the Foo class:
class Foo a b c | a -> b where
foo1 :: a -> b -> c
foo2 :: a -> c
and when I call foo2, everything works fine. The compiler knows which instance to use because of the dependency.
But if I remove the dependency to create Foo':
class Foo' a b c where
foo1' :: a -> b -> c
foo2' :: a -> c
everything still compiles fine, but now whenever I try to call foo2' GHC throws an error about not being able to resolve which instance to use because b is ambiguous.
Is it ever possible to call foo2' without error? If so, how? If not, why doesn't it generate a compilation error?
It is impossible to call foo2' in this context, because, as Daniel Fischer says, there is no way to determine which instance to use. For example, if you had:
instance Foo' Int Int Int where
foo2' x = x
instance Foo' Int Bool Int where
foo2' x = x + 1
Both of these foo2's have the same type signature, so there is no way to determine which one to call.
The usual way around this problem is to use a proxy:
data Proxy a = Proxy
class Foo'' a b c = where
foo2'' :: Proxy b -> a -> c
Which you use like so to select which instance:
foo'' (Proxy :: Proxy Bool) 42

Type annotation in a typeclass' default value causes a "could not deduce" type error

This is a beginner's question, but I cannot recognize any answer to it anywhere.
The following code:
class A a where
foo :: a
class A a => B a where
bar :: a
bar = (foo :: a)
fails to compile in GHC, with the error message:
Could not deduce (A a1) arising from a use of `foo'
from the context (B a)
bound by the class declaration for `B'
...
GHC seems unconvinced that all the a's in the definition of typeclass B are the same. Can anyone please explain what exactly its line of reasoning is?
Removing the type annotation in line 5 avoids the problem of course, but I would still like to understand what is going on here...
You should indeed get rid of the type annotation. Type variables are not scoped in Haskell, so (foo :: a). Is interpreted as "have foo produce a value of type a for any type a", which cannot be done as foo will only produce values of those types a that are in the class A.
Put differently, your declaration of B is equivalent to
class A a => B a where
bar :: a
bar = (foo :: c)
That is, there is no connection between your use of the type variable a and the other uses in the declaration.
Dropping the explicit annotation solves your issue:
class A a => B a where
bar :: a
bar = foo
Now, the compiler can figure out for what type you want to invoke foo, i.e., for the type a that you wrote in the signature of bar and that appears in the head of the class declaration.
The Glasgow Haskell Compiler (GHC) comes with an extension that allows for scoped type variables. With that extension enabled, your fragment is type checked like you originally expected:
{-# LANGUAGE ScopedTypeVariables #-}
class A a where
foo :: a
class A a => B a where
bar :: a
bar = (foo :: a)
Prelude> :set -XScopedTypeVariables
Prelude> :{
Prelude| class A a where
Prelude| foo :: a
Prelude| class A a => B a where
Prelude| bar :: a
Prelude| bar = (foo :: a)
Prelude| :}
Prelude> :t bar
bar :: B a => a
Prelude>
but as dblhelox said, it's not really necessary to use scoped type variables here.

Resources