3 ms·
> “sure, but most haskell programs leave type annotations out, it's only some specific parts where it enhances clarity ” This is very false, I can tell you fro
by mlthoughts2018 8y ago
> “sure, but most haskell programs leave type annotations out, it's only some specific parts where it enhances clarity ”
This is very false, I can tell you from having written Haskell in production for several years. It’s widely regarded as an anti-pattern in Haskell to leave out type annotations, even for constant values, except in the most trivial of cases.
Type annotations are a design feature of Haskell. You usually use the “type” keyword to define custom type names for primitive types just to give them descriptive, application-specific names, like
type PhoneBook = [(Name, Number)]
just so you can add more explicit annotations and communicate the flow of your program very explicitly in the type annotations.
You definitely do not look at it like minimally using type annotations “only where it adds clarity” because the whole point is that as the code author you don’t know where clarity is needed. That is for the code reader who has to change your work later on.
Incidentally, I actually very much think that your first example of that for loop at the bottom is a lot clearer than the one using auto.
Just make a descriptive typedef / typename of that long const_iterator type. Make something readable so that we know why there is a vector of pairs of (float, int).
If you want to cut down the syntax there, auto is not the right way. A descriptive typedef is the right way using type alias names that communicate your intended design.
- jcelerier 8y ago> You definitely do not look at it like minimally using type annotations “only where it adds clarity” because the whole point is that as the code author you don’t know where clarity is needed. That is for the code reader who has to change your work later on. Are you serious ? In standard Haskell you can't even add type annotations to bindings, that's how much type annotations are relevant to the language. They're only available in type & function definitions. I seriously doubt that you use {-# LANGUAGE ScopedTypeVariables #-} and that all of your code looks like main = let (x :: Integer) = 123 in print $ x That's literally what you expect C++ programmers to do when you ask them not to use auto, and I've absolutely never seen production Haskell looking like this - common Haskell is much closer to this : https://github.com/ivanperez-keera/haskanoid/blob/master/src/Game.hs https://github.com/ivanperez-keera/haskanoid/blob/master/src....
- mlthoughts2018 8y agoNah. ScopedTypeVariables is extremely commonly used, and Haskell as a language is one where frequent use of extensions is common generally. Saying “you can’t even add type annotations to let bindings” shows a misunderstanding of Haskell, because you can and the way the language accomplishes it is with ScopedTypeVariables. It’s not “special” or “extra” in Haskell, using extension pragmas is just a super common, mundane, every-day thing in Haskell. I should also point out that when you say > “They're only available in type & function definitions.” you are wrong. Firstly, you can (and should almost always) use type annotations for plain values, like pi :: Float pi = 3.14 and e.g. with more complex data constructors like in < https://en.m.wikibooks.org/wiki/Haskell/Type_declarations https://en.m.wikibooks.org/wiki/Haskell/Type_declarations > section on constructor functions. For value constructors that use complex type dynamism in Haskell, like the return value polymorphism in Haskell regular expressions, it’s critical to use type annotations on plain values, because the type annotation actually resolves which of the polymorphic return types will be chosen. Secondly, and more importantly, you can use type annotations on bindings natively in a where clause, and this is a very fundamentally important thing to do, especially for locally defined helper functions. Then you only need ScopedTypeVariables if your helper function needs to involve a generic type constraint from the polymorphism of the outer function declaration, which is vastly more rare. I’d also say the comparison with the types of local variables that tend to be unannotated in Haskell let or where clauses is very disingenuous and it’s actually not similar to the iterator boilerplate example you gave before at all. When all the arguments have well-annotated types, and you use a let or where variable to hold a temporary value, the type is inferred by a reader much more easily than when using auto in C++, and has a direct meaning in terms of the calculation at hand (e.g. it’s not done to reduce boilerplate like auto). For example, if you’re trying to calculate distance between two tuples (x0, y0) and (x1, y1), where the types of those tuple elements are given explicitly just a few lines up, then there is little harm in doing something like where dx = x1 - x0 though it’s still preferable to say e.g. where dx = x1 - x0 :: Float This is emphatically not what you’re doing with auto, because the types are not otherwise locally obvious, and even if they were, a judicious use of typedef / typename saves just as much syntax while being far more descriptive.
- 8y ago