I'm on a real logic programming kick lately. I had dabbled in it years ago, but this time I'm really spending some time on it. Logic programming is a mind-expanding experience, since it really is a different paradigm for computation. Once you've learned the functional and imperative styles, do yourself a favor and pick up some Prolog. It definitely failed in the marketplace, and always had more traction in Europe than it did in the US, but it's worth your time if you are into programming.
A few minutes ago, I was thinking about how my 30-min day-session chart of the S&P500 e-minis doesn't divide the day up evenly. There are 405 minutes in a traditional S&P pit session (from 8:30 to 3:15 Central time), so 30-minute slices leave the last bar covering only 15 minutes. To find out which bar lengths would divide the day evenly, I pulled up my prolog interpreter and asked:
between(1,405,Len), 0 is 405 mod Len.
... and it gave me all the numbers that divide evenly into 405, one at a time. I think the query reads very naturally, even if you don't know the language. This particular program isn't that hard to write in any language. For instance, in haskell we can write:
filter (\x -> 405 `mod` x == 0) [1..405]
[ x | x <- [1..405], 405 `mod` x == 0 ]
Looking at the prolog and haskell side-by-side, I can say they are both concise, both will only compute as many of the numbers as you want to consume, and both are easy enough to understand. Still, I can't help but appreciate how the prolog one sticks better to the problem domain. It almost literally says: "Len is between 1 and 405, and divides evenly into 405. What could Len be?" That may not seem much simpler than the haskell, but think about it: I didn't have to tell prolog to use a list, and I didn't have to tell prolog I needed to filter a list down to compute my answer. Instead, I just described the numbers I was interested in, and asked prolog to figure it out for me. When the problem is a lot more complicated than this one, I can appreciate being able to stay more in the problem domain and out of the implementation details.
There's no free lunch, though, so what you give up when you stay above the implementation level is control over the performance. When the prolog code is fast enough, great. When it's not, you can optimize it to a degree but you will eventually hit a brick wall because prolog has no mutable variables and no arrays. But, for cases where speed is paramount, you can drop to C and call into it via your prolog's FFI.