Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Instead of repeating the same thing over again with more words, perhaps you can explain why it's "in the spirit" of Haskell not to know the return type (except with the vagueness of "Object") of a function in this one case.


I explained how you do know the return type, it is of some known, universally quantified type variable.

A type variable is a compile-time known type.


There's a difference between a type like Object and a polymorphic type. This is easy to see with generics in a Java-like pseudocode:

    public foo(Object o) { ... }
is very different from

    public foo<A>(A o) { ... }
In Haskell, you always use the second style of function--there is no sub-typing, so there is no real equivalent to the Object type in Java.

We can imagine something similar for read. If we didn't know anything about the type, it would look something like this:

    public Object read(String s) { ... }
instead, it's actually something like this:

    public A read<A>(String s) { ... }
So whenever you use read, you would be specifying the type it returns. I imagine it would look something like this:

    read<Integer>("10") + read<Integer>("11")
This is exactly how read works in Haskell. The important difference, however, is that the type system can infer what type read is supposed to be. So the above code snippet would look like this:

    read "10" + read "11"
If you made the types explicity, it would look like this:

    (read "10" :: Integer) + (read "11" :: Integer)
So you always know what type read has when you use it. But what is the type of read itself? The Javaish version looked something like A read<A>(String str). The important part is the generic A: it's a polymorphic type variable. In Haskell, the type is similarly polymorphic: String -> a.

Of course, the type isn't quite this general: you can only read things that you have a parser for. In the Java-like language, it would probably look roughly like:

    public A read<A extends Read>(String str) { ... }
In Haskell, we do not have any concept of "extending" a type: there is no sub-typing of any sort. Instead, we have typeclasses which serve the same role, so the type ultimately looks like this: read :: Read a => String -> a.

Hopefully this clarifies how you know what type read has. Really, it's no different from any other class like Show. There is a very clear parallel between show and read:

    read :: Read a => String -> a
    show :: Show a => a -> String
Being able to take advantage of this sort of symmetry in the language is extremely useful. My favorite example is with numeric literals, which are polymorphic:

    1 :: Num n => n
In my previous Java pseudocode, this would look something like:

    1<A>
and would be used like:

    1<Integer> + 1<Integer>
    2<Double> * 3<Double>
Of course, this is hideous, which is why type inference is so important.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: