Custom typeclass instance

I have a data type Book that is an instance of custom typeclass Printable that has a function print. The print function returns Text that I want to print using debug statement. However, I am not able to print it directly with

   debug $ print myBook -- this gives error

But if I first assign the function’s return value to a variable and then use debug, it works.

   printOut: Text = print myBook 
   debug printOut -- this works

Can you please suggest what could be the issue here, and why do I need to assign it to a variable before printing?

Here is the full code and the error statement:

data Book = Book with 
    title: Text
    author: Text 

class Printable i o where 
    print: i -> o 

instance Printable Book Text where 
    print aBook = "Title: " <> aBook.title <> " by " <> aBook.author

testPrintable = script do 
    let 
        myBook = Book with 
            title = "Learn you a Daml"
            author = "Digital Asset" 

        printOut: Text = print myBook 

    --debug $ print myBook -- this gives error
    debug printOut -- this works
 
    return()

The error message:

    • Ambiguous type variable ‘b0’ arising from a use of ‘debug’
      prevents the constraint ‘(Show b0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘b0’ should be.
      These potential instances exist:
        instance (Show a, Show b) => Show (Either a b)
          -- Defined in ‘GHC.Show’
        instance Show BigNumeric -- Defined in ‘GHC.Show’
        instance Show (Numeric n) -- Defined in ‘GHC.Show’
        ...plus 30 others
        ...plus six instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In a stmt of a 'do' block: debug $ print myBook
      In the first argument of ‘script’, namely
        ‘do let myBook = ...
            let printOut : Text = print myBook
            debug $ print myBook
            debug printOut
            ....’
      In the expression:
        script
          do let myBook = ...
             let printOut : Text = print myBook
             debug $ print myBook
             debug printOut
             ....typecheck
1 Like

Essentially, you have the problem with multi-parameter typeclasses described here; where the ambiguous variable in that article is m, you have o being ambiguous.

debug does not sufficiently constrain o; consider its signature.

The standard solution is exactly the one in the followup article, a “functional dependency” or “fundep”. However, keep in mind that this is dependent [sorry] on your specific typeclass semantics, i.e. using a fundep here will make it so each choice of i can have one and only one Printable, not a bunch with different o choices. (That is, after all, the promise you are making when you declare the fundep “o is determined by i”.)

Fundeps are commonly used in the Daml standard library, e.g. HasExercise.

Thanks @Stephen !

So is it correct to say that the problem is with the debug function and not the way I have defined the Printable type-class? I am not sure how I can ‘constrain’ o in its definition.

Note: my conclusion above is based on just your response. I will read up the articles you linked later as they look like some heavy-lifting!

@Neelam_Dwivedi
Here’s how you can do it

class Printable i o | i -> o where 
    print: i -> o

Thanks @a_putkov :star_struck: