4 ms·
> Go model a square and a rectangle in your favorite statically typed language. Okay. data Shape = Square Int | Rectangle Int Int deriving (Show) > You wi
by codygman 12y ago
> Go model a square and a rectangle in your favorite statically typed language.
Okay.
data Shape = Square Int | Rectangle Int Int deriving (Show)
> You will find that square extends rectangle and setting the length on a square also sets the width.
Why? I don't really see a need for square to extend a rectangle.
> So if I have a collection of rectangles which contains an unknown number of squares of which I set the width on each of them.
Like this?
> let unknowns = [(5,4),(3,2),(4,4)]
> let toShape (x,y) = if x == y then Square x else Rectangle x y
> map toShape unknowns
[Rectangle 5 4,Rectangle 3 2,Square 4]
Tomorrow I'll see if I can make this type-safe by using dependent typing as shown in: [0][1][2]
This was easily solvable in my staticly typed language as you can see. In something like Idris I could have
very easily encoded the toShape function the the type signature.
0: http://www.alfredodinapoli.com/posts/2014-10-13-fun-with-dependent-types-in-haskell.html http://www.alfredodinapoli.com/posts/2014-10-13-fun-with-dep...
1: https://www.fpcomplete.com/user/konn/prove-your-haskell-for-great-safety/dependent-types-in-haskell https://www.fpcomplete.com/user/konn/prove-your-haskell-for-...
2: http://jozefg.bitbucket.org/posts/2014-08-25-dep-types-part-1.html http://jozefg.bitbucket.org/posts/2014-08-25-dep-types-part-...
- pfultz2 12y agoThats cool. Here's the somewhat equivalent in C++: struct square { int x; }; struct rectangle { int x; int y; }; boost::variant<square, rectangle> to_shape(int x, int y) { if (x == y) return square(x); else return rectangle(x, y); } std::vector<std::pair<int, int>> unknowns = { {5, 4}, {3, 2}, {4, 4} }; auto shapes = unknowns | boost::adaptors::transformed(boost::fusion::make_fused(to_shape)); Of course, the structs are not polymoprhic and can't be printed out. I just left that out because it requires a little more code to do that. Obviously with haskell its much less code. I would very much be interested in the dependently typed version.
- codygman 12y agoCool, it's always good to see other languages approaches (especially when idiomatic) to try out their way of thinking. > I would very much be interested in the dependently typed version. I'll try to get to it later today, I'm pretty busy until then.
- he_the_great 12y agoAnd the same thing in D: struct Square { int sideLength; } struct Rectangle { int length; int width; } import std.variant; alias Shape = Algebraic!(Square, Rectangle); import std.typecons; auto to_shape(Tuple!(int, int) shape) pure nothrow { if (shape[0] == shape[1]) return Shape(Square(shape[0])); else return Shape(Rectangle(shape.expand)); } void main() { auto unknowns = [ tuple(5, 4), tuple(3, 2), tuple(4, 4) ]; import std.stdio; import std.algorithm; writeln(unknowns.map!(to_shape)); } [Rectangle(5, 4), Rectangle(3, 2), Square(4)]
- codygman 12y agoI've been debating whether or not to choose C++ or D to learn as my "when performance really matters" language. I'm still going to learn Rust, but I'm very interested in D. I also like that it has a pure keyword ;)
- nickbauman 12y ago> I don't really see a need for square to extend a rectangle. Except that a square is-a rectangle! Especially in terms of geometry. So you should be able to use this isomorphism in a type system as a perfect isomorphic mapping this is the entire purpose of the Liskov Substitution Principle. But the polymorphic result doesn't work polymorphically in a way that helps people reason about how the system works. It does things that are "correct" from a LSP and static typing system POV, but isn't helpful.
- codygman 12y agoI'll admit I'm a little rusty on my geometry, but I'm fairly sure I was never told that a square is a rectangle. If you mean insofar as operations on rectangles should work on squares, this could be accomplished with typeclasses.
- nickbauman 12y agoAh ha! Now you see the problem. Whether or not a square is a rectangle in a Euclidian sense it is a normal thing to use a type system in this way. And yet a discussion of it has emerged to whit this exchange. Gives one pause about the value of type systems for correctness eh?
- codygman 12y ago> Whether or not a square is a rectangle in a Euclidian sense it is a normal thing to use a type system in this way. Why do I care about whether or not it's normal way (for some people/languages) to use a type system in this way? I care about reality and having my types reflect it precisely. > Gives one pause about the value of type systems for correctness eh? I actually don't see how. It seems like you are saying "regardless of whether a square is a rectangle in reality, people (mis)use type systems to say this". Someone’s misuse of a tool doesn't call the tools value into question. Basically, I may not be able to model your exact relationships in the exact same way but I can model real world concrete things in the type-system which obtains the same or more flexibility and maintainability.