Nested ambiguously typed methods

  • A+
Category:Languages

Say I have a class

class T where     tag1 :: String     tag2 :: String 

With ambiguous types enabled, I could specify each of them in an instance:

instance T A where     tag1 = "tag1"     tag2 = "tag2" 

If I want to make tag2 append something to tag1, I can define

instance T A where      tag1 = "tag1"     tag2 = tag1 @A ++ " suffix" 

This works great, but if I want tag2 to always append suffix to each tag1, I seem to have to specify the ambiguous call for each instance.

I understand the need for this, as tag1 from any instance would work for each call. However, is there any trick within haskell for me to specify it once only?

Something like

tag2 :: T a => String tag2 = tag1 @a ++ " suffix" 

 


Your code currently does not compile since the type class has no type parameters, so I'm going to assume your code is actually (assuming AllowAmbiguousTypes is enabled)

class T a where     tag1 :: String     tag2 :: String 

Now you can provide a default implementation for tag2:

class T a where     tag1 :: String     tag2 :: String     tag2 = "tag2" 

But this does not meet the requirement of adding the suffix to tag1.
We could try this(assuming TypeApplications is enabled):

class T a where     tag1 :: String     tag2 :: String     tag2 = tag1 @a ++ "suffix" 

Now this won't compile, and the compilation error will be

error: Not in scope: type variable `a' 

and rightfully so, the type a isn't defined anywhere. However, we want to refer to the a in the head of the class, for this we need the language extension ScopedTypeVariables, and with that the code will compile and you'll get the results you expect (I suggest reading up the linked documentation)

Here's a full program that demonstrates the usage:

{-# LANGUAGE TypeApplications, AllowAmbiguousTypes, ScopedTypeVariables #-}  class T a where   tag1 :: String   tag2 :: String   tag2 = tag1 @a ++ " suffix"  data A = A data B = B  instance T A where   tag1 = "tagA"  instance T B where   tag1 = "tagB"   tag2 = "tagB overriden"  main = do   putStrLn $ tag1 @A   putStrLn $ tag2 @A   putStrLn $ tag1 @B   putStrLn $ tag2 @B 

And the output is:

> ./foo tagA tagA suffix tagB tagB overriden 

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: