I'm an intermediate Python dev and just starting out with Haskell. It seems like Python's classes can be used in a way that is similar to how Haskell's typeclasses are used. It seems like typeclasses are just a way to implement operator overloading. Like this:
# main.py
class MyClass:
def __init__(self, num, name):
self.num = num
self.name = name
def __str__(self):
return self.name
def __radd__(self, other):
self.num + other
def __add__(self, other):
self.num + other
Now when you do something like
# main.py
c = MyClass(1, 'hello')
c2 = MyClass(2, 'foo')
str(c) # 'hello'
sum([c, c2]) # 3
Now lets compare this to Haskell:
-- main.hs
data MyClass = Foo | Bar
instance Show MyClass where
show Foo = "foo"
show Bar = "hahahahaha"
Now I can do something like:
show Bar -- "hahahaha"
My newbie (at best) knowledge tells me that the only advantage to using Haskell (if one is comparing only these two language features) is that the Haskell programmer is capable of defining n
"operators" to overload whereas Python has a fixed list
But this cannot be the whole story. What are the other differences? What am I missing here?
-
5You may want to clarify "It seems like Haskell's typeclasses can be used in a way that is similar to how Haskell's typeclasses are used."Weaver– Weaver03/24/2016 22:31:50Commented Mar 24, 2016 at 22:31
1 Answer 1
One difference: In Python, you can define a subclass MySubclass
of MyClass
, and then you can freely add objects of MyClass
with objects of MySubclass
.
Haskell tends to avoid subtyping: if you have a typeclass Addable
with a function add :: Addable a => a -> a -> a
, both summands must always be of the same type. It can be any type that is an instance of Addable
, but it must be the same for both summands and the result.
Another difference: in Haskell you can "retroactively" make a type an instance of a typeclass. For example you can create a typeclass and declare instances for some preexisting types that fit the mold. In Python, when you define a class you must list what classes it will extend.
Yet another difference: in Python, "method dispatch" (what method implementation is actually executed in an invocation) is determined by the object receiving the invocation. Haskell typeclasses allow dispatching on the expected return type of a function. A clasic example is the function read :: Read a => String -> a
. Depending on the desired type a
of the result, different reading functions will be called.
This a good talk on Haskell typeclasses which, from minute 40 onwards, compares them to OO interfaces.
-
1Great answer, except for the retroactive part. You can do this in python, as in most dynamically-typed languages. That's definitely a major difference from OO interfaces in statically-typed languages, though.Karl Bielefeldt– Karl Bielefeldt03/25/2016 03:41:02Commented Mar 25, 2016 at 3:41
-
@Karl Bielefeldt Thanks for the correction; I didn't know you could do that in Python.Daniel Díaz Carrete– Daniel Díaz Carrete03/25/2016 07:41:06Commented Mar 25, 2016 at 7:41
-
2
Haskell tends to avoid subtyping
- Haskell doesn't have subtyping.Daenyth– Daenyth03/25/2016 15:19:05Commented Mar 25, 2016 at 15:19 -
both summands must always be of the same type
i thought you could add a function (operator overload) in the typeclass definition?dopatraman– dopatraman03/25/2016 15:46:04Commented Mar 25, 2016 at 15:46 -
@dopatraman Here's an example of what I meant. In Haskell, the function
(+) :: Num a => a -> a -> a
is overlodaded and works for any type that is an instance ofNum
. The expression(1::Int) + (1::Int)
typechecks, and so does(1::Float) + (1::Float)
. But(1::Int) + (1::Float)
does not typecheck; you need to perform a explicit conversion.Daniel Díaz Carrete– Daniel Díaz Carrete03/25/2016 16:18:58Commented Mar 25, 2016 at 16:18