|
|
queensnake
10 points
1 day ago
Doesn't using the data structures demand a complete tearing out and remodelling of your mind, though? Personally I've gotten through the smaller stuff (zip, foldr, blah, heavy recursiveness) but I started stalling at having to relearn from scratch, how to go about manipulating the usual data structures. |
| permalink parent |
|
|
cgibbard
155 points
1 day ago
*
Oh, certainly. You really do have to take a second look at everything. Data structures in a lazy language are (or at least can be) a whole lot more like control structures, with the list taking the place of the loop. Learning Haskell generally demands a complete tearing out and remodelling of your mind, if you're coming from an imperative background. It's worthwhile though, because you end up with a much cleaner perspective on everything. One of the most basic things which you can do with an algebraic data structure is to replace all the data constructors in it with functions of appropriate arity and type, but which instead of producing that datatype again, might produce some other type of value. A function which does such a replacement is known as a 'catamorphism'. For lists, this is the right-fold:
It recursively replaces each cons
For another example consider the following tree type:
In case you have trouble reading that, it basically says that a value of type
represents the tree:
We can write a catamorphism (fold) for this type as follows:
Suppose we wanted to write the function which gives a preorder traversal of the tree, as a list. We could write that as follows:
This replaces the tree structure with list structure in the appropriate way. One can also write this as:
which first replaces the tree structure with function structure, and then applies the resulting function to the empty list. This has better performance because it avoids repeatedly appending with (++) (which takes time on the order of the size of the left parameter). Or to sum up the elements of the tree:
Or to compute the maximum of 0 and the elements of the tree:
Or how about flipping the tree over left to right?
Or once we get into dealing with monads (you might feel like skipping this one, down to the horizontal line, if you haven't seen anything about monads yet), the tree might hold actions to be performed, say, returning the value Left u if the left branch of the tree is to be followed next, or Right u for the right branch.
Here, we replace tree structure with program structure. The result is a way to run a sort of decision tree, each action deciding which of the child trees should run, and collecting up a list of the results. So the general idea to take from this is that data constructors can be thought of as temporary place-holders to be filled in with other functions later, and data structures would then represent whole control flows waiting to happen. Another issue is that immutable data structures can require a little more thought to design in the first place, but when well-designed generally can compete quite favourably with mutable ones performance-wise (typically with only a logarithmic factor performance hit). There are some fairly general solutions in this regard, such as finger trees (it's a package on Hackage), with which it's possible to implement an almost-magically-fast Sequence , and things like priority queues (which unfortunately haven't made their way into the libraries yet). Also, Data.Set and Data.Map provide very good implementations of general sets and finite maps using binary balanced trees. Of course, you can do mutable data structures in Haskell too, using STRefs or IORefs in place of pointers, but you tend to want nice immutable ones because they're so much simpler to reason about (even if they're slightly more work to define, if you can't find a way to build on other structures that already exist). Personally, I've found the stuff that's already in the libraries provides pretty decent coverage for most applications, in terms of low-level structures that you might need. |
| permalink parent |
|
|
Korollary
48 points
1 day ago
You have comments that are more detailed than most people's blog posts. Get a blog or else the baby seal gets it. |
| permalink parent |
|
|
jleedev
9 points
1 day ago
*
Well, you can change BLOG to CLUB in four steps:
Scary, isn't it? |
| permalink parent |
|
|
babyseal
27 points
1 day ago
Please do what he says mister! I think he really means it!!! |
| permalink parent |
|
|
queensnake
11 points
1 day ago
*
Thanks much, I appreciate that. edit: Note, all, the one book I've seen on this . |
| permalink parent |
|
|
pl0nk
10 points
7 days ago
*
Amen. I'm working on modifying a complex algorithm right now. It has no formal specification and only one reference implementation, written in C++ by a guy who naturally no longer works here, and which does lazy evaluation and caching in order to be useful on actual datasets. The actual algorithm is quite hard to discern among all the carefully ordered state changes, and due to the fact that caching isn't built as a layer on top, but in fact threaded throughout the computation as incremental side effects. There is not a good separation of concerns . Since it's so difficult to reason about, trying to fix it feels like reaching inside and jiggering the wires. "Seems to be working now, ship it!" Ugh. My ideal scenario would be to have enough time to write a purely functional reference implementation and use that as a baseline for (a) changing the algorithm in the first place, (b) unit-testing the crazy C++ one. Oh, luxury of time... |
| permalink parent |
It's kind of a difficult question to answer -- what any given general-purpose language is good for. There are a few things that Haskell is particularly good at (as other people have pointed out to some extent), but it's really the general aspects of the language which make it pleasant to program in, rather than it being particularly well suited to certain applications.
There are some more general things which it is particularly good at, but which aren't directly application domains. These are things which might be useful in just about any context. I'll list a few:
This is just a few of the things I could say about it. Picking specific applications is a confusing way to express what the language is good at, because the things at which Haskell really excels would apply to almost any program.
If I had to summarise, it's particularly good for programs which need to be correct (who really likes bugs anyway?), and also those which need to use concurrency or parallelism.