Nikita Volkov
Nikita Volkov

Reputation: 43310

Getting a TypeRef of a function result type

Following is my failing attempt to extract a TypeRef of b:

import Data.Typeable

f :: Typeable b => a -> b
f = impl
  where
    bTypeRep = typeOf $ (undefined :: Typeable b => (a -> b) -> b) impl
    impl = undefined

The error message is following:

Could not deduce (Typeable a0) arising from a use of `typeOf'
  from the context (Typeable b)
    bound by the type signature for f :: Typeable b => a -> b
    at src/Xet.hs:14:6-25
  The type variable `a0' is ambiguous

What is wrong? How to solve this?

Upvotes: 1

Views: 127

Answers (2)

hammar
hammar

Reputation: 139840

The problem is that type variables are not scoped in standard Haskell, so there is no connection between the type variables in the signature of f and those in your type annotation. You might as well have written

bTypeRep = typeOf $ (undefined :: Typeable d => (c -> d) -> d) impl

The solution, as luqui suggested in the comments, is to enable the ScopedTypeVariables extension. Note that this doesn't make all type variables scoped; you have to use explicit forall quantifiers to indicate to the compiler when you want type variables to be scoped.

{-# LANGUAGE ScopedTypeVariables #-}

import Data.Typeable

f :: forall a b. Typeable b => a -> b
f = impl
  where
    bTypeRep = typeOf $ (undefined :: Typeable b => (a -> b) -> b) impl
    impl = undefined

Upvotes: 2

Nikita Volkov
Nikita Volkov

Reputation: 43310

The following has solved the issue. Thanks to luqui.

{-# LANGUAGE ScopedTypeVariables #-}

import Data.Typeable

f :: forall a b . Typeable b => a -> b
f = undefined
  where
    bTypeRep = typeOf $ (undefined :: b)

I'm willing to accept another answer explaining, why the forall a b . part makes the difference, and possibly other solutions.

Upvotes: 0

Related Questions