What do you mean add two of the same things together exactly? If I'm not mistaken, what you are talking about is possible but I don't totally understand what you are saying. Could you provide an example?
The types of polymorphism are different. Haskell's parametric polymorphism is compile-time polymorphism, Go's interfaces are run-time polymorphism.
If we draw a parallel to C++, Haskell's polymorphism is like templates, Go's interfaces are like abstract base classes (except that they use compile-time duck typing).
For example, consider the (+) function in Haskell:
(+) :: Num n -> n -> n -> n
If you use an Integer as the first argument, the second argument must also be an integer, as well as the return type. You can observe this by currying, binding only the first argument:
In Go, you could write an interface Num and define a function:
func foo(a Num, b Num) Num
However, if float64 and int both implement the Num interface, you could also foo a float64 and int. And it would return something that conforms to the Num interface, but what type is actually constructed depends on the implementation of foo.
In other words, type classes have relatively little to do with Go interfaces, aside that they both implement a (different) form of polymorphism.
It's possible to make something akin to Go's polymorphism in Haskell, but you'd need to hide the type parameter of the typeclass using existential quantification.
data NumBox = forall n. Num n => MkNumBox n
You can now use the NumBox for runtime polymorphism:
Prelude> :type [1::Int, 4.4::Double]
[...]
Couldn't match expected type `Int' with actual type `Double'
[...]
Prelude> :type [MkNumBox (32 :: Int), MkNumBox (22.32 :: Double)]
[MkNumBox (32 :: Int), MkNumBox (22.32 :: Double)] :: [NumBox]
> If we draw a parallel to C++, Haskell's polymorphism is like templates
It's important to note that even if Haskell's classes feel like C++ templates they are actually implemented more like abstract classes. In C++ you essentially create a new function for each template instantiation. In Haskell the function is passed an additional pointer telling the function how to implement the class. Kind of like a vtable pointer except not bound to the actual object. This has performance implications, so it's an important point to remember when comparing the languages.
GHC is pretty good at specializing type-class-using functions for particular instances, e.g. if you have
fac :: (Num a, Eq a) => a -> a
fac 0 = 1
fac n = n*fac (n-1)
main = do
x <- readLn :: IO Int
print (fac x)
it will create a specialization (without any indirect calls)
fac_Int :: Int -> Int
and call that (in fact, in this case fac_Int will even be implemented by a worker function of type Int# -> Int# (unboxed ints)).
If you don't want to rely on this automatic optimization, you can always add a pragma {-# SPECIALIZE fac :: Int -> Int #-}.
(I used a recursive example because a non-recursive function would usually simply be inlined, avoiding any indirect calls too, assuming the call site is monomorphic).
That's a good point, however, the important aspect of typeclasses is that they're type-checked, not that they're compiled via monomorphization. Also, I believe that the way that typeclasses are compiled is at the discretion of the compiler, so actually typeclasses may be compiled in the same way as C++ templates. Another point is that monomorphisation isn't always possible, because a function could be run with an infinite number of types.
He's talking about the inability to specify an interface that specifies functions that take two arguments of the same type. Go can't do that.
You can sometimes work around it. For instance consider sorting. The natural approach is to specify a type that allows comparisons. Go can't do that. But in go you can have a collection which has a function Less(i, j int) bool that takes in two integers and compares the objects at those positions (which in turn just happen to be of the same type).
But this is a limited work around, and there are plenty of cases where you can want something more flexible.