[Haskell-beginners] Explicit specification of function types
divisortheory at gmail.com
Tue Mar 24 20:51:06 EDT 2009
On Tue, Mar 24, 2009 at 6:02 PM, Peter Verswyvelen <bugfact at gmail.com>wrote:
> 2009/3/24 Brandon S. Allbery KF8NH <allbery at ece.cmu.edu>
>> That's my understanding, F++ types don't require any runtime lookups so
>> inference can't surprise you.
> It uses .NET interfaces for that, but the F# expert book mentions they
> would like to have type classes in a future version of the language.
>> in Haskell can do unexpected things: F++ has parenthesized function
>> arguments, so it will catch too few/too many arguments directly, but
>> Haskell's uncurried function call notation almost guarantees strange errors
>> in those cases even if you have everything explicitly typed.
> Not really, F# has both curried and uncurried forms, just like Haskell.
> It is true that F# encourages automatic generalization without type
> signatures. You never need to give one, even for exported modules.
> But the lack of type classes has its price. E.g.
> add x y = x + y
> What is the type of add in F#?
> Well, that depends on the first usage of this function... Give it Ints and
> it becomes add :: Int -> Int -> Int, and you can't use it on Doubles any
> more. Very confusing, since you can use the overloaded (+) on any type.
> These are current limitations of the language.
> At least that what I understood from it...
What you say is partially true. For example, if delcared as you typed it, a
rule similar to the monomorphism restriction (from what I understand of the
monomorphism restriction) applies. If it's never used, x and y are of type
int, and if they are used, x and y pick up the type of whatever you call it
with. So doubles if you invoke it with 3.0 and 4.0, ints if you invoke it
with 3 and 4, and an error if you invoke it once with doulbes and once with
The F# answer to this is to "inline" the function. For example:
let inline add (x:'a) (y:'a) : 'a = x+y
let result1 = add 3 4
let result2 = add 3.0 4.0
Hover over this declaration of add to get its type and you see "add : 'a ->
'a -> 'a (requires member (+))
Here, result1 is an int and result2 is a double. I haven't heard this from
straight from the developers, but I suspect inlining is necessary due to the
.NET Framework's support for reflection. Consider, for example, what would
happen if you tried to obtain the method add via reflection and there was
code for exactly 1 add method present in the binary. The code would have no
reasonable way to behave. By inlining, I believe it inserts multiple
definitions of hte function into the code, similar to what you get when you
instantiate a C++ template.
Anyway, a bit off topic, but at the very least I'm starting to understand
why it's ok in F# but not really so much in Haskell. The issue of
documenting the function I think is kind of a non issue actually, because if
it were really just for the purposes of documentation you could just comment
out the the type signature so that it's still visible but not interpreted by
the compiler. In F# though the documentation is even less of an issue since
you get automatic mouse-hover type definitions. The same thing applies to
the issue of detecting type errors. It's pretty easy to find them when all
the type inference mismatches are underlined for you on the fly. But in
Haskell it seems the problem of finding type errors is made more difficult
not only by the lack of a helpful syntax underliner, but also by the
typeclasses, which make the errors even more far removed from what you would
expect. Not to mention the performance penalties associated with making
something too generic, which I didn't think of originally.
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the Beginners