8 ms·
> Because the types are known, there's an incredibly powerful testing framework called QuickCheck that is capable of e.g. generating tens of thousands of valid
by Ingon 13y ago
> Because the types are known, there's an incredibly powerful testing framework called QuickCheck that is capable of e.g. generating tens of thousands of valid inputs and seeing if it can automatically disprove your assertions about your code. Python's typing is insufficient for this.
I think immutability also helps on this front.
- SamReidHughes 13y agoJust being statically typed helps, there's nothing particularly special about Haskell that makes QuickCheck possible.
- coolsunglasses 13y agoHave you read the source to Haskell's QuickCheck? It can automatically derive automatic randomized generation of your data-types FOR you. No other generative testing library (such as for Clojure or Erlang) can do this. Further, the random data generation can be customized using the functional combinator API. Haskell QuickCheck's source code is a compelling example of what can be done with static types and typeclasses in Haskell.
- SamReidHughes 13y ago> It can automatically derive automatic randomized generation of your data-types FOR you. There's nothing about Haskell (or some extension to Haskell, I presume) that makes this possible that wouldn't make this possible in other languages like C#, Java, or, with a bit more verbosity, C++. If I'm wrong, please say what it is, I'd love to know.
- coolsunglasses 13y agoYou're wrong and you should look into how typeclasses, derivation, SYB, and GHC generics work. That they aren't doing it is reason enough. Clojure and Erlang's QuickCheck libraries would derive Arbitrary if they could. :)
- SamReidHughes 13y agoI already know how they work. Still waiting for an explanation of what they can do that you couldn't do in Java or C# or (with some verbosity) C++. Edit: For example, to answer this question, you could define a type and explain how Haskell lets you automatically generate arbitrary instances of that type, where Java or C#, being as limited as you claim them to be, would be incapable of doing so. Edit: Also, Clojure and Erlang are irrelevant. My comment you originally replied to said that static typing was what makes QuickCheck possible.
- revcbh 13y agoLet's use circles and rectangels to motivate some analysis. In Haskell you might define: data Point = Point { x :: Float, y :: Float } deriving(Generic) data Shape = Circle { center :: Point, radius :: Float } | Rectangle { topLeft :: Point, bottomRight :: Point } deriving(Generic) In C# you could similarly define class Point { public float _x, _y; public Point(float x, float y) { _x = x; _y = y; } } interface Shape {} class Circle { public Point _center; public float _radius; public Circle(Point center, float radius) { _center = center _radius = radius } } // etc, for Rectangle ... Let's start from the C# end of things. Let's say we want to do some tests on random Shapes and that we want to get an instance of a random shape by calling Generate.random<Shape>(). There are a couple of different ways to do this. We could explicitly define a RandomShapeFactory and a RandomPointFactory and then wire those up into the Generate class. Maybe we could use reflection to dynamically generate instances of Points and Shapes from their definitions at runtime. It would probably end up looking like some combination of the two. Haskell doesn't let you magically generate random instances of Shape. The cool thing it gives is the "deriving(Generic)" part. Effectively, this causes the compiler to generate a description of Point and the Shape-Circle-Rectangle set of types. In many ways, it's like C#'s reflection. The QuickCheck library uses this reflection-like definition to generate random instances. The core functionality isn't very different, but Haskell's approach has a number of advantages. Most importantly, it's type-checked at compile-time. In the C# version, I could call Generate.random<Cat> and the code would blow up at run-time, whereas we would just get a compiler error in Haskell. The other major advantage in this case is the reduction of boiler-plate. There's no need to register factory instances inside of some singleton object at startup, the type system can infer which Generic components are needed where. C# and Haskell are both turning complete, so you can do anything in either language. Haskell makes certain types of programming more enjoyable by reducing boiler-plate and preventing annoying runtime errors. EDIT - code formatting
- Locke1689 13y agoHmm, I think you could do something similar to QuickCheck using C# generics. The biggest problem you'd run into is probably the same as Haskell does (the expression problem). You can get some ideas from http://www.daimi.au.dk/~madst/ecoop04/index.html http://www.daimi.au.dk/~madst/ecoop04/index.html. Oh and you could probably always fall back to reflection and attributes, but that's just kind of cheating isn't it? ;)
- solomatov 13y ago>Hmm, I think you could do something similar to QuickCheck using C# generics You can't do this. Quick check can generate type classes instances, for example, for tuples, functions, etc. This is impossible in language like C#.
- SamReidHughes 13y agoNo it's not. The feature C# calls reflection lets you inspect types and generate them automatically.
- solomatov 13y agoIf we use reflection, we might know about error only in runtime. What haskell does is guaranteed to work at compile time. That's why it's so cool.
- Locke1689 13y agoThere are certainly cases which aren't expressible(things which require kinding, for example) but your examples aren't a problem. Both tuples and functions can be represented using System F, and thus can be completely transposed into C# generics. I believe you don't understand C# generics and you should look closer at the fundamental type calculus.
- coolsunglasses 13y agoImmutability is good but far from enough.