One of my goals is to improve the packaging of some complex pipeline I'd built. It involves Flash (not my choice!), PHP (I'm innocent!), Java (for GATE), Scala and Haskell. The Scala and Haskell parts are my fault, mostly a refusal to go back to writing Java. What's funny about the pipeline though is that it's essentially Java, with a thin bit of Scala which is really just calling this one dinky component written in Haskell. Making people install a Haskell compiler just for that dinky component is stupid. In my defence, writing said dinky component in Haskell was probably the right thing to do, in other words, use the tools you know best to get the job done and out the door. But now that we have a little bit of time to put into packaging it up nicely, I'm trying to replace that little dinky with of Haskell with Scala. This way all the backend bits run on JVM and we have simpler dependencies.
It's also a good way for me to learn the language a little bit better. I guess I've reached a stopping point for the week. I've reimplemented the shallow part of my code which defines a bunch of data types, parses from XML and pretty prints the output. If you want to take a look, the Haskell and Scala code are not identical (the XML parsing may be a bit better in Scala version, due to reimplementation?) but I think they are roughly comparable.
The deep part is the bit that does graph traversals, basically simplifying RMRS semantics into subject-object-predicate triples. That bit I'll have to try and implement next week.
Things I've learned so far:
- always use case classes, never use new: I was wondering why for some classes, like Option, I could just call the constructor (eg. Some), but for others I had to write new Foo(...). Turns out that it was just because I wasn't declaring my classes to be case classes. Using case classes means I get to avoid all the confusing stuff that mutability gives you, for example, having to worry about the distinction between equality and identity.
- I may not be using traits right, but I think I like Haskell type classes better simply because with type classes, I can separate the instance declaration/definition from the class definition
- subtypes make for easy heterogeneous lists: in Haskell I'd wrap the things I want in some existential type E and then make a list of E. In Scala, I make my types all extend the trait E. For some reason, I find the latter a bit "easier", either more memorable/clear or just more convenient
- to get methods associated with classes rather than objects, just create a singleton object (that extends the desired trait)
- Scala lets you pattern match XML: it's kind of neat that you can interleave XML in your code and do things like pattern matching on it.
I get the impression that you basically have two kinds of Haskeller. The first is the kind that uses Haskell because they can take on a lot of abstraction and use it to do amazing things, the smart Haskeller. I think I fall more into the dumb category of Haskeller who tends to use it because I find the consequences of subtyping (Liskov substitution) and mutability to be too confusing. And maybe there are also smart-dumb Haskellers... the kind who fall into both camps simultaneously.
