2

I'm trying to use undefined to get value of type constant (something like sizeOf in storable).

module Main where

class MyClass a where
    typeConst :: a -> String
    -- ^ Argument is ignored

class TryRead a where
    tryRead :: String -> Maybe a

newtype ByLen a = ByLen a

-- | Make all types under ByLen readable, if their typeConst's are longer then 3 characters
instance (Read a, MyClass a) => TryRead (ByLen a) where
    tryRead = if len > 3
                then Just . ByLen . read
                else const Nothing
      where
        len = length $ typeConst (undefined :: a)

instance MyClass Int where
    typeConst = const "moreThan3"

main :: IO ()
main = go (tryRead "214234" :: Maybe (ByLen Int))
  where
    go Nothing = print "Nothing :("
    go (Just (ByLen i)) = print i

However, this gives an error:

Could not deduce (MyClass a0) arising from a use of ‘typeConst’
from the context (Read a, MyClass a)
  bound by the instance declaration at src/Main.hs:13:10-49
The type variable ‘a0’ is ambiguous
Note: there is a potential instance available:
  instance MyClass Int -- Defined at src/Main.hs:20:10
In the second argument of ‘($)’, namely
  ‘typeConst (undefined :: a)’
In the expression: length $ typeConst (undefined :: a)
In an equation for ‘len’: len = length $ typeConst (undefined :: a)

I don't understand what problem with type deducing is there, considering I specified type for typeConst argument explicitly as a type variable, which is bound by MyClass a, so it should in my mind have no problems applying to typeConst function.

3
  • 9
    You need to use the ScopedTypeVariables extension: otherwise the a in the where clause is not recognized as being the same one as the one bound before but rather a fresh type variable (hence the a0 vs. a issue). Commented Apr 8, 2016 at 23:39
  • @gallais Thanks, that works. Now waiting for someone to write it as an answer. But I read some about this extension and I now don't get why is it working without explicit forall? (I tried something like that inside non-class function and it didn't. compile until I added a forall) Commented Apr 9, 2016 at 9:36
  • My guess is that an instance declaration is a bit of a special case: if you declare instance forall a. (...) => MyClass (Maybe a) for instance then you get a Malformed instance error. Commented Apr 9, 2016 at 10:43

1 Answer 1

3

You need ScopedTypeVaribales extension to be enabled for this to work either through a ghc flag -XScopedTypeVariables or through a pragma at the top of the file:

{-# LANGUAGE ScopedTypeVariables #-}

If it used within a class instance, nothing special needs to be done, because type variables from the head of the class are already in the scope, but if you would like to use it in simple top level function you will need an explicit forall in the type signature.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.