For a function a -> Integer
there's only one behaviour which is allowed - return a constant integer. Why? Because you have no idea what type a
is. With no constraints specified, it could be absolutely anything at all, and because Haskell is statically typed you need to resolve everything to do with types at compile time. At runtime the type information no longer exists and thus cannot be consulted - all choices of which functions to use have already been made.
The closest Haskell allows to this kind of behaviour is the use of typeclasses - if you made a typeclass called Foo
with one function:
class Foo a where
foo :: a -> Integer
Then you could define instances of it for different types
instance Foo [a] where
foo [] = 0
foo (x:xs) = 1 + foo xs
instance Foo Float where
foo 5.2 = 10
foo _ = 100
Then as long as you can guarantee some parameter x
is a Foo
you can call foo
on it. You still need that though - you can't then write a function
bar :: a -> Integer
bar x = 1 + foo x
Because the compiler doesn't know that a
is an instance of Foo
. You have to tell it, or leave out the type signature and let it figure it out for itself.
bar :: Foo a => a -> Integer
bar x = 1 + foo x
Haskell can only operate with as much information as the compiler has about the type of something. This may sound restrictive, but in practice typeclasses and parametric polymorphism are so powerful I never miss dynamic typing. In fact I usually find dynamic typing annoying, because I'm never entirely sure what anything actually is.