What's going on in Haskell?

Definition of receipt:

"In Haskell, a derived instance is an instance declaration that is generated automatically in conjunction with a data or new type declaration. Derived the body of the derived instance declaration syntactically from the definition of the associated type."

I really don't get it, to be honest.

The code below is taken from: Link

data BaseballPlayer = Pitcher 
                        | Catcher
                        | Infielder
                        | Outfielder
                        deriving Show

barryBonds :: BaseballPlayer -> Bool
barryBonds Outfielder = True

barryInOf = print(barryBonds Outfielder)

      

My question is what does the inference statement do in this particular case, and what does the inference-expression do in general?

This question is not a duplicate: how does haskell work in OBS: I am not asking how it works in terms of source code, I am asking what it does.

+3


source to share


3 answers


In this particular case, it generates an instance Show

for your type as shown below:

instance Show BaseballPlayer where
    show Pitcher    = "Pitcher"
    show Catcher    = "Catcher"
    show Infielder  = "Infielder"
    show Outfielder = "Outfielder"

      

This way values ​​of the type BaseballPlayer

can be converted to string, for example. on print

.

The string is chosen so that it is a valid Haskell expression that can be restored to its original value upon evaluation.

The general case is a little more complicated, but follows the same idea: converting a value to a string of a Haskell expression. For example,



data T = T Int (Maybe Bool) deriving Show

      

will make the instance so that

show (T 1 Nothing) = "T 1 Nothing"
show (T 2 (Just 3)) = "T 2 (Just 3)"

      

Note how the parentheses are also generated in the latter case. This is done using a member of the class showsPrec

, but it is not that important.

+5


source


In short:

deriving

automatically implements functions for several types of Haskell classes such as Show

and Eq

. It can't be done with arbitrary types, but the ones it deriving

works for are simple enough to automatically implement.

The Show

typeclass defines functions to represent data types as String

.

In details:

Are you familiar with classes?

https://www.haskell.org/tutorial/classes.html

Typeclasses are similar to interfaces in Java: they define several functions that any data type that wants to use those functions can implement can implement.

For example, let's say we have a class like this:

class Comparable a where
    lessThan :: a -> a -> Bool
    equalsTo :: a -> a -> Bool

      

Beware of the word class

. This means that the Haskell customization is using the text type, not the typical "class" you would hear in object-oriented languages. a

here is a type of filler similar to how you would expect templates to work in C ++ and generics to behave in Java.

Let's say we define a data type like this:

data Color = Red | Green | Blue

      

To make it Comparable

work with Color

, we will implement instance

Comparable

:



instance Comparable Color where
    lessThan Red   Green = True
    lessThan Red   Blue  = True
    lessThan Green Blue  = True
    lessThan _     _     = False

    equalsTo Red   Red   = True
    equalsTo Green Green = True
    equalsTo Blue  Blue  = True
    equalsTo _     _     = False

      

Roughly speaking, this now allows you to "compare" Red

, Green

and Blue

with each other. But was there some way that GHC could automatically assume that this was exactly the "order" you wanted?

Taking a step back, the typeclass Show

has a similar structure:

https://hackage.haskell.org/package/base-4.9.1.0/docs/src/GHC.Show.html#Show

class  Show a  where
    showsPrec :: Int -> a -> ShowS
    show      :: a   -> String
    showList  :: [a] -> ShowS

    showsPrec _ x s = show x ++ s
    show x          = shows x ""
    showList ls   s = showList__ shows ls s

      

Something to note is that functions within a typeclass can be defined with each other. Indeed, we could just as easily do:

class Comparable a where
    lessThan :: a -> a -> Bool
    equalsTo :: a -> a -> Bool

    greaterThan :: a -> a -> Bool
    greaterThan lhs rhs = not (lessThan lhs rhs && equalsTo lhs rhs)

      

However, the key point is this: For arbitrary user-defined class types, GHC has no idea how their functionality should be implemented when you try to bind a type class to a data type such as Color

or BaseballPlayer

. For some types, such as Show

, Eq

, Ord

, etc., where the functionality is quite simple, the GHC can generate standard implementation, which of course you can overwrite your own.

Indeed, experiment by trying to compile the following:

data Color = Red | Green | Blue deriving (Comparable)

      

As a result, I get the following:

test.hs:9:43:
    Can't make a derived instance of ‘Comparable Color’:
      ‘Comparable’ is not a derivable class
      Try enabling DeriveAnyClass
    In the data declaration forColor
      

Certainly some GHC extensions can be used to increase the power deriving

, but for another day :)

+5


source


Inference means that your datatype can automatically "infer" instances for certain class classes. In this case it BaseballPlayer

outputs Show

which means that we can use any function that requires an instance Show

to work with BaseballPlayer

.

Automatic retrieval makes it easier for you to work with the template. The most common types of classes to get automatically are Show

and Eq

, because the compiler can make very reasonable values ​​for these types.

+3


source







All Articles