Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to say a data of type A is also of type B in Haskell?

Tags:

haskell

I am learning haskell and am having trouble following the line of thought. I am trying to think in C++ terms and I am unable to find the equivalent of C++ subclass in Haskell. How do I say data B is also data A for simple structs A and B?

Background: I have read LearnYouAHaskell at least thrice. I am able to write basic Haskell code, but nothing very advanced and am fairly experienced working in C++.

Attempts: I was trying to think in terms of defining A as a type class and making B an instance of A. However, I don't want to write new definition of the method/data member and just want to use the definition of A. I am unable to comprehend the error messages.

-- Trial.hs 

class A a where 
    data_member :: Int 

data B = B { 
    x :: Int 
}

instance A B;
Trial.hs:2:9: error:
    • Could not deduce (A a0)
      from the context: A a
        bound by the type signature for:
                   data_member :: A a => Int
        at Trial.hs:2:9-26
      The type variable ‘a0’ is ambiguous
    • In the ambiguity check for ‘data_member’
      To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
      When checking the class method: data_member :: forall a. A a => Int
      In the class declaration for ‘A’
like image 400
Pratyush Rathore Avatar asked Sep 12 '19 15:09

Pratyush Rathore


2 Answers

Like Damian suggests, use a Sum type: The | type operator/constructor.

Using ADT (Algebraic Data Types) is a great strength of Haskell. Dive blindlessly into using them whenever you can, I think all programmer learning haskell with an Imperative background come to this same conclusion: ADT are incredibly useful and concise.

Coming from a C++ background, when I first groked the Sum type I was translating it to C++ in my mind this way:

data PureVirtualClassA = ConcreteClassB Member1 Member2 | ConcreteClassC Member3

where Member1, Member2, and Member3 would be the types of a struct member. You can simplify this example with all the three being Int:

data PureVirtualClassA = ConcreteClassB Int Int | ConcreteClassC Int

(If you want a named data member, you should go for using Records, but they are not always needed)

Now you can use it in a function, just like you would use C++ polymorphism, where ConcreteClassB and ConcreteClassC would be deriving from PureVirtualClassA:

myFunction :: PureVirtualClassA -> Int
myFunction (ConcreteClassB x y) = x + y
myFunction (ConcreteClassC z) = z

IMPORTANT NOTE: In those examples for the C++ programmer I have used the word Class with the C++ meaning! Don't use the word Class this way in Haskell. A class in Haskell is something different, it's more like an interface, but the comparison does not stand.

like image 79
Stephane Rolland Avatar answered Oct 14 '22 08:10

Stephane Rolland


You can create a new type containing both:

data A = A Int
data B = B Int

data AB = MakeA A | MakeB B

:t MakeA $ A 4
MakeA $ A 4 :: AB
like image 37
A Monad is a Monoid Avatar answered Oct 14 '22 08:10

A Monad is a Monoid