2

In oop, such as java, we can only downcast a super class into subclass when the type actually is the subclass.

But In haskell, we can simply 'downcast' a type class into any instances of that type class. Such as fromInteger which return a Num. From my point of view, it actually is a Int so it cannot be 'downcasted' to Float but it can.

Prelude System.Random> :t fromInteger a
fromInteger a :: Num a => a
Prelude System.Random> fromInteger 12 :: Int
12
Prelude System.Random> fromInteger 12 :: Float
12.0

Another example is to change Random into Int, Float and even Bool

Prelude System.Random> let (a, g) = random (mkStdGen 12) :: (Int, StdGen)
Prelude System.Random> let (a, g) = random (mkStdGen 12) :: (Double, StdGen)
Prelude System.Random> let (a, g) = random (mkStdGen 12) :: (Bool, StdGen)

We don't know what Random actually is, but we can just 'downcast' it into type of the instance, and it works 100% all the time. I don't understand why it works.

code4j
  • 4,208
  • 5
  • 34
  • 51
  • 4
    This has nothing to do with the casting you are comparing it to. First, everything happens statically at compile time. There is no discerning wether an object "actually is the subclass". Second, there is no subclass-superclass-relationship here at all. It's more like an interface `INum` which is implemented by `Int`, `Float` etc. and contains a method `fromInteger`. The conversion is defined in an arbitrary way in `fromInteger`, without a connection to classes. – firefrorefiddle Aug 12 '13 at 10:45
  • This SO topic might have some useful insights and references for you: http://stackoverflow.com/questions/11420126/does-haskell-have-return-type-overloading – rkhayrov Aug 12 '13 at 11:02
  • @rkhayrov i will read about it :) – code4j Aug 12 '13 at 13:41

3 Answers3

8

I think you've gotten confused by mistakenly viewing typeclasses as OO classes and associating type inheritance with them. Typeclasses are very different and there's no type inheritance in Haskell, which btw isn't a weakness at all. Your examples actually demonstrate quite a lot of Haskell's power.

Let's analyze the definition of random:

random :: RandomGen g => g -> (a, g)

It has a signature g -> (a, g), which says that it takes some value g and returns some value a and some value of the same type as the input g, there are no specific types like Int or Char specified in this signature, a and g are polymorphic, meaning that they can be of absolutely any type. Then comes the constraint part RandomGen g =>, which says that actually g can be only of a type which has an instance of a typeclass RandomGen, right under the interface of the class I've linked to you'll find a list of its instances defined in the module and it will contain only RandomGen StdGen, so basically we can see g as StdGen. Then look again at the random function to find out that it actually is defined as part of the interface of a typeclass Random, which is parameterized by a type variable a, which we've already met in the signature of a function random, so this implies a Random a constraint on the definition of function random. Also see that this class in a list of its instances contains Random Int, Random Double, Random Bool.

Now let's return to your examples. By specifying a type random (mkStdGen 12) :: (Bool, StdGen) you're telling the compiler to see random as random :: StdGen -> (Bool, StdGen), from which it simply deduces, which instances of RandomGen and Random to use. Those instances actually define the type-specific behaviour of the functions, which in turn guarantees that any compilable code will make sense.

As you see, it all has absolutely nothing to do with casting.

Nikita Volkov
  • 42,792
  • 11
  • 94
  • 169
  • 1
    Thanks for your explanation :) 。 Oh, I got totally wrong. There is no casting, it's only polymorphism. They are so called polymorphic functions(?), and it has different implementations with different instances, and different return types with different instances. And :: is to specify which instances we want. – code4j Aug 12 '13 at 13:40
  • Yes, functions containing any polymorphic arguments are referred to as polymorphic as well. Yes, it's instances where type classes actually get their parameter-specific (the `a` in `Random a`) implementations. No, the return types of type class' functions do not necessarily need to depend on the instance - a simple example is a type class `Show a`, which declares a function `show :: a -> String`. No, the `::` is only used to tell the compiler, which type a preceding expression has, but in most situations the compiler will be able to infer it, it's just that your case was an exception. – Nikita Volkov Aug 12 '13 at 14:20
2

From my point of view, it actually is a Int

This is where you are wrong. There is two different implementation of fromInteger: Integer -> Int and Integer -> Float. There is absolutely no Int involved in fromInteger 12 :: Float.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
1

As you can see from the comment of @MikeHartl Haskell type classes are not classes in OOP sense. Nor they are interfaces. In your case it may be useful to view them as C++ template classes with all methods static:

template <typename T>
class Random
{
public:
   static std::pair<T, StdGen> random(StdGen a);
}

The "casting" is not "casting" at all but an explicit qualification of template parameter:

std::pair<Int, StdGen> a = Random<Int>::random(mkStdGen 12);
std::pair<Int, Bool> a = Random<Bool>::random(mkStdGen 12);

Same goes for Num:

template <typename a>
class Num
{
public:
   static a fromInteger(Integer b);
}

int a = Num<int>::fromInteger(Integer(2222));
complex a = Num<complex>::fromInteger(Integer(3333));
nponeccop
  • 13,527
  • 1
  • 44
  • 106
  • thanks for the answer. But i don't know cpp template. It's something like java generic function? But as far as I know. Java generic function is for the type checking of compiler. And it will downcast actually at runtime. – code4j Aug 12 '13 at 13:46
  • I don't know Java unfortunately :( The method is static (doesn't have an instance reference), so there's nothing to downcast. – nponeccop Aug 13 '13 at 00:27