4 ms·
> Even given a simple thing like foo:: int -> int -> int, there's really no way to tell what it's doing. Ahh, this is an important point. The reason you can't
by mightybyte 13y ago
> Even given a simple thing like foo:: int -> int -> int, there's really no way to tell what it's doing.
Ahh, this is an important point. The reason you can't tell what it's doing is because it is quite concrete. One really cool thing about this kind of type system is that the more generic your functions, the more you can tell about what it's doing. Consider this function:
foo :: (a, b) -> a
There's only one possible thing this function can do! And there's only one possible implementation--the correct one. This is the case because the types involved are completely general. Type signatures can communicate a lot more than one might think.
- GeneralMayhem 13y ago>There's only one possible thing this function can do! That's not at all true... it can do all sorts of transformations on the first value of the tuple. I suppose without type restrictions on the parameters it can't do too much because there are relatively few functions defined on all types, but then, how often are you going to see a function signature that vague? More likely, you'd see `foo :: MyClass a => (a, b) -> a` or `foo :: (MyType, b) -> MyType` which opens up the possibilities considerably, because you don't know which of MyType's behaviors is being invoked.
- tel 13y agoThat's exactly it: (a) there are no functions at all defined on all types except id (of type (a -> a)) and (b) you end up seeing signatures close to that vague all the time. This is exactly the power of parametricity.
- eru 13y ago> [...] you end up seeing signatures close to that vague all the time. That's not an accident. Factoring out little helper functions like this is considered a virtue in Haskell (and acording to Paul Graham, also in Lisp). Even if you only use them once---because they make reasoning easier.
- tel 13y agoAgreed! I think the tendency to highly parametric functions comes from several sources. First, good programming practice allows for decomposing entities and leading to more flexible functions. Second, once you have higher kinded types you realize that 90% of programming is wiring between contexts and is more parametric than people think. Finally, HM typing auto generalizes all of your let bindings which means your compiler can inform you of opportunities for genericity that you weren't even aware of... so long as you ask.
- kenferry 13y ago> foo :: (a, b) -> a > There's only one possible thing this function can do! Ah, so it scales a vector by a scalar returning a new vector, right?
- judk 13y agoNo, it is impossible to write the function you described on that type. There is no function "scale" that works polymorphically on any type 'a'. The parent you are responding to is quoting a proven result of computer science.
- jlarocco 13y agoBut what percentage of "real world" functions work on completely generic types? In reality most useful functions take more specific types, and those types allow many more operations to be performed on them. In general, it's not really possible to tell what a function does just by looking at the type signature.
- flebron 13y agofoo = undefined And all its brothers :)
- jlarocco 13y agoThat's all well and good with a trivial function like foo :: (a,b) -> a, but for most non-trivial functions it won't be so obvious, and that's exactly when it's most helpful to know what's going on.
- nightski 13y agoa.) Many functions in Haskell are this trivial. map, fold, etc... b.) Functions that are non-trivial will have additional constraints often hinting exactly at what the function does. Most important is not the fact that you can write poor Haskell code which does not exibit this self-documenting behavior, but rather that if you choose to exploit the type system it has the expressiveness to allow you to do so! (and enforce it) If you are working with a Haskell library and see a function with the signature (IO Int) you may start to question your choice of library :) The only problem is, once you get a taste of this power it is easy to yearn for even more such as dependent types (i.e. Agda, Idris...)