2,468 karma · joined March 2, 2008
That said, I do feel that the type of testing I do in Haskell is often quite different from other languages. Due to the strict type system, some types of errors can be eliminated at compile time, and thus do not need to be tested for. Of course, as the parent pointed out, some people take this to a (very awesome) extreme, but even in a less rigorous form the static guarantees can eliminate many things that I would write unit tests for in other languages.
Finally, you may also be interested in SmallCheck, an alternative to QuickCheck. From its documentation:
> The big difference [between SmallCheck and QuickCheck] is that instead of using a sample of randomly generated values, SmallCheck tests properties for all the finitely many values up to some depth, progressively increasing the depth used. For data values, depth means depth of construction. For functional values, it is a measure combining the depth to which arguments may be evaluated and the depth of possible results.
This means that SmallCheck will often find small and interesting counterexamples to the properties you wish to affirm. (As an aside, note that writing property-based tests is a skill, just like writing good unit tests.)
tl;dr: Testing can sometimes be less necessary, but is certainly not unnecessary, and there are some very high quality and well-documented libraries for testing in Haskell.
func reverse<C : CollectionType where C.Index : BidirectionalIndexType>(source: C) -> [C.Generator.Element]
and the following example as "good" non-generics: func reverse(source: CollectionType) -> CollectionType
However, you can have equally clean syntax with generics. For example, consider the hypothetical syntax: func reverse(source: CollectionType[a]) -> CollectionType[a]
in which `CollectionType` is parameterized by the type variable `a` [0].I also take issue with the idea that removing static checks isn't a big penalty. In particular, I cringe a little at the following sentence
> Because it does not actually matter. If an Int gets in my array, it’s because I screwed up and likely had very poor testing around the scenario to begin with.
The benefits of static typing is that you don't need testing of things like that. The compiler guarantees safety, allowing you to avoid writing test case that are mundane and boring, such as checking that you don't put an Int into a String array.
The following paragraph also seemed questionable to me:
> Yes, in this example, I’ve moved the validation from compile-time to runtime. But you know what, that’s likely where many of these types of errors are going to be coming from to begin with because the content of the array is being filled in with dynamic content getting coerced into your given type at runtime from dynamic input sources, not from a set of code statements appending items to your arrays.
I think this is somewhat incorrect. You should never just be type-casting your inputs. (In fact, I think it should ideally be impossible to do so without the compiler generating really big flashing warnings saying "THIS IS DANGEROUS!"). The static verification here will prevent you from doing silly things, and should ideally force you to do input validation at the location of input, instead of blindly casting things to the type it needs.
All in all, not a bad discussion, but I think that this piece demonstrates that bad implementations of static typing can severely detract from the good qualities of static typing, and that it takes some getting used to to program well in a statically typed language (not casting things spuriously is a good example of that). That said, I know very little about Swift, so take all of this with a grain of salt.
[0] It may at this point be clear that the inspiration here is Haskell and ML; I am a big proponent of these languages, and believe that static typing can eliminate many common errors.
Guess this is what causes culture clash :)
Completely agreed on the difference between language issues and community issues. From my perspective, the Haskell community does great with language issues. With GHC 7.10 we'll have AMP and OverloadedRecordFields, and I've seen a ton of work go into getting GHC ready for something like Backpack (throughout this summer). I think eventually these things will be solidified into a Haskell2018 or something, at which point a lot of the issues with Haskell-the-language that I've encountered when writing industry-style code will be gone. And I think that's great, and points to a bright future for Haskell; I don't think any other language has ever made me excited by the pace of progress in the language itself. (Some may say that in other languages you don't need to be excited by the next compiler release because the current one is good enough, but all languages have warts and deficiencies -- I think the GHC devs and the Haskell community do a great job finding these and trying to find clever and principled ways of improving them. See OverloadedRecordFields.)
However, I think community questions like the pipes libraries , cabal hell (to a lesser extent -- I think this is partially a tech problem that Backpack-like modules will solve), problems with the Prelude, etc, are an even bigger issue. Sadly, I think those issues are actually much harder. For instance, in the Haskell community, we constantly have issues with Strings being the default datatype for text, because Strings are just [Char]. This is a pretty terrible model for text most of the time (not all of the time, but most of the time). However, changing this requires not only changing the base library, but also hundreds of other libraries on Hackage. Some of these are likely unmaintained, and would break and stay broken. There are many ways in which I think the Haskell Prelude could be fixed (String -> Text conversion, fmap -> map and mappend -> ++ renaming, getting rid of confusing Control.* and Data.* heirarchies, etc), but the undertaking is gargantuan, because any of these changes would affect hundreds of libraries (some now unmaintained) in the ecosystem. And because of this, I've seen no plans or proposals on how Haskell should handle these sorts of changes.
Fixing Prelude is just one of the more difficult "community questions". We have a proliferation of very similar but competing libraries, which in some ways is good (people have choice, different libraries can make different design decisions, etc), but in some ways is bad (if I write a library that does streaming, I have to make a pipes version and a conduit version, or choose one). Again, Backpack modules will help here. Same goes for Haskell-to-Javascript compilers. However, with many of these, I think time will tell -- we have multiple options that are constantly evolving because we haven't really figured out the "right" way to do things yet, and eventually things will settle down.
As always, some of the hardest problems in programming are not actually coding problems, but people problems. Hopefully we can find a way going forward to find solutions to those as well.
Could you clarify the license / money situation?
Disclaimer: IHaskell author here :)
(To be fair, I'm reading one side of the story via the link above, but assuming that the facts there are actually true...)
http://ezyang.com/jfp-ghc-rts-draft.pdf
It's just a draft but it's pretty great.
[0] http://andrew.gibiansky.com/blog/machine-learning/hessian-fr...
[1] http://machinelearning.wustl.edu/mlpapers/paper_files/icml20...
As an aside, everything in IPython 2 is available from the keyboard and all shortcuts can be viewed by pressing the Help menu or 'h'. 'Add cell above' is now just 'a' (and below is 'b') when in command-mode. I expect that learning to use the new modal interface can be a bit of a hassle, but for me it turned out to ultimately be really awesome.
IHaskell is aiming to be (in a sense) a replacement for GHCi for interactive Haskell development. It uses the IPython framework (no Python code in main codebase, of course) in order to provide an interactive notebook interface. It allows multiline expressions, graphical output for things like JSON, charts, images, etc, and is very extensible. It's more or less stable but there's still a ton to do if anyone is interested - feel free to get in touch!
[0] http://andrew.gibiansky.com/blog/ipython/ipython-kernels/
(And if anyone has an interest in contributing, please get in touch!)
In particular, speeding is a norm in many places in the United States. If you are not going five to ten miles above the speed limit, people are likely to be actively passing you or driving too close behind you. I suspect it's safer to go five miles above the speed limit than have people constantly passing you because you're going slower than everyone else. (That said... I do wish speed limits were limits, and everyone followed them perfectly.)
A principal ideal domain is a ring in which every ideal is generated by only one element, so whenever we see (a, b), we know there is some element c such that (a, b) = (c). I think this is what vog meant by having a "real" GCD - only in a principal ideal domain is your gcd unique. Without uniqueness, we can still define a greatest common divisor such that if gcd(a, b) = g, we know that there is nothing we can multiply by g to get a divisor of both a and b; that is, there's no extra factor we can add to g in order to get another factor of both a and b. That is enough to call g a GCD - but it's not necessarily unique! It turns out that in rings which aren't principal ideal domains, you can have more than one GCD! It's bizarre to think exactly what "greatest" means in this context, but you can also just think of it as "can't add any more factor while still dividing both a and b".
Ring theory is fun! (And practical, sometimes - you can describe some algorithms very elegantly via embedding the things you're working with in unusual rings.)
More info, with some examples and counterexamples:
https://en.wikipedia.org/wiki/Principal_ideal_domainIf you consider the ring of the integers, then the ideals are multiples of some integer. For instance, the multiples of three are an ideal, because multiplying a multiple of three by any integer yields a multiple of three (so if you multiply the set of multiples of three by any integer, you just get back something that's in the ideal).
The final point is this: the ideal generated by two integers is actually just the set of multiples of their gcd. Therefore, if a and b are integers, (a, b) is the set of multiples of their gcd - just like (3) is the set of multiples of three. This is why the gcd is often written in this way.
The cool thing is that this works in rings in general, not just integers. You can extend the concepts of gcd, primality, divisibility, etc to rings in general, and operate on things besides just integers, such as matrices, polynomials, or rotations of a cube.
For more info:
http://en.wikipedia.org/wiki/Ring_theory
http://en.wikipedia.org/wiki/Ideal_(ring_theory)(Disclaimer: I'm not a photographer, and the only thing I know about photography is what I learned in college computer vision courses and overheard from friends.)