http://blog.tmorris.net/understanding-practical-api-design-static-typing-and-functional-programming/
When I'm satisfied with a program, it has this ethereal property that
if the problem is slightly altered, the program is only slightly
altered.
One thing I find with Haskell: the type system really seems to help
guide the program towards having that property, by making sure all the
parts fit together cleanly.
Case in point:going to incorporate the extra 8 register from
64 bit pentium into a pre-existing 32 bit Pentium assembler.
(Which is a in fact a somewhat large messy change that would
trigger a rewrite in most assemblers.)
I'd hope that such a change would be easy in a well-designed assembler.
I much doubt if e.g. the whowonordraw gives a compile time error
on a non-finished board, that the program can be robust against
a small change of the rules. Say strikes going through the lower
left square are not counted as a win.
Eh? No, that kind of change is trivial, and wouldn't affect the types
at all. Maybe you're imagining the rules of tic-tac-toe being encoded
in the types, which could in fact be done, especially in fancier systems
like Agda's. But all that we're talking about here is that creation of
values describing game states is reserved to the API implementation by
the module system. The API doesn't export the constructors for values
in the "game state" types. It's just like an OO system that enforces
private instance variables, so that clients can only get at those
variables through accessor functions supplied by the instances.
Then there are static typed languages like Forth where the programmer
is the judge whether there is a type error, and type errors are not
generated by the compiler.
That is not static typing in any normal sense of the term. Forth is
untyped.
A much more natural api is where a board is an object.
You can send a move message -> accepted or nor
You can send an inspect message -> won lost draw or not-finished.
If you attempt a move on a finished board, that is a programming
error. By suffering some extra complexity in the types, you can catch
this particular error at compile time, decreasing your testing
and support burden at runtime. Whether that trade-off is worth it in
practice depends on the problem. For tic-tac-toe it's probably
not worth it except as an exercise, and this tic-tac-toe problem
was in fact presented as an exercise.
I can make that totally robust without storing lost or draw
information using the type system.
I think the exercise simply wanted separate types for complete and
incomplete games, not separate types for win/lose/draw. I could imagine
wanting separate types for wins/losses/draws if there were functions to
award prizes to the winners of games. You'd want to make sure that lost
games didn't get awarded these prizes.
He requires that on several calls, if the data is wrong, you get
a compile time error. How could that be a reasonable demand from
a language like Python where the call can be made interpretively?
You can't, that's the entire point, Python is good for many things but
not for this. So if you want to expand your horizons as a programmer
enough to be able to do this sort of problem, you have to try out more
languages.
Of course it is an exercise. But I think that it went this way:
1. solve it in Haskell
2. require incidental and non-useful features of the solution
to work in other languages the same way.
Not sure what you mean there. The exercise was to use static types to
write an API with certain characteristics. Obviously you can't do that
without static types. It's just like programming exercises involving
writing recursive functions can't be solved in languages like Fortran(?)
that don't support recursion, etc.
And those characteristics (per the specification in the exercise) were
not incidental or non-useful, they were essential.
If he is bashing Scrum, I'm bashing staic typing.
I don't remember what if anything he said about Scrum.
I give you that. Mastering a functional language is a real
step, but I don't think this tic-tac-toe exercise will entice me to
do that.
Functional programming and fancy type systems are separate subjects and
Haskell implements both. Scheme is functional without static types, and
I got interested in Scheme some time before starting to use Haskell.
When I did try out Haskell, I got more from its type system than I
expected to. I thought the following was really cool:
https://gist.github.com/2659812 with discussion at:
http://www.reddit.com/r/haskell/comments/ti5il/redblack_trees_in_haskell_using_gadts_existential/
it implements a data structure (red-black trees) with complicated
invariants that are expressed in the type system in a natural way, so
that the compiler ensures that all manipulations on the trees don't mess
up the invariants.
Maybe the solutions to
http://projecteuler.net that are published
in Haskell sometimes condensing a few pages of my sequential code in
a few lines, will inspire me to take up Haskell.
I've done some Euler problems in Haskell but so far, my solutions
haven't used types in particularly interesting ways. Project Euler is
mostly about problems in number theory and combinatorics, and Python is
great for that. Haskell may have more attraction if you like abstract
algebra or mathematical logic. Here is a really nice article that
explains Haskell's type system in terms of categories:
http://en.wikibooks.org/wiki/Haskell/Category_theory