In Haskell you'd do something like:
skip [] = []
skip ("a":xs) = skip (drop 2 xs)
skip (x:xs) = x : (skip xs)
Which makes it super clear that you're skipping over items in the list. The parsing then simply becomes: map parseLine (skip lines)
Which is at least an order of magnitude clearer and doesn't mix a bunch of unrelated logic together.Even worse, the original author says the goal of his code is to:
> The goal is to skip the line after a line starting with the letter "a".
But he actually skips two lines after an "a". The above Haskell code makes it clear that we're skipping two lines with "drop 2".
Using lists and recursion just further lends itself to this style.
In op's example, he's simultaneously tracking loop state, figuring out which lines to parse, and parsing those lines. It's a very imperative way to do it. I'd prefer to look at the problem through another lens:
Q1: What is he doing?
A1: Parsing a subset of lines.
Q2: How do you determine the subset of lines?
A2: Skip lines that are equal to "a" and two lines after that.
That's what led to the two sections of my code. Concerns have been separated.If I was forced to use arrays and, furthermore, work in an imperative language, I'd still have one function to parse the lines and one function to figure out which lines to parse.
In Python, first compute which indices are of interest:
def indices(xs):
i = 0
while i < len(xs):
if xs[i] == "a":
i += 3
else:
yield i
i += 1
And have a separate place for actually parsing each line: [parseLine(lines[i]) for i in indices(lines)]
This translates relatively nicely to Haskell as well, though definitely feels a little forced / unnatural: indices lines = indices' 0
where indices' i
| i >= (length lines) = []
| shouldSkip = indices' (i + 3)
| otherwise = i : (indices' (i + 1))
where shouldSkip = (lookup i lines) == Just "a"
[parseLine <$> (lookup i lines) | i <- (indices lines)]Thanks for the answer. I must say that I find the original problem quite artificial.
import Control.Lens.Cons
case uncons v of
Nothing -> .. empty vector ..
Just (head, tail) -> ..I am right that this will extract consecutive views of the original array as pairs of (item, slice) elements? I guess array elements need not be copied, but there will still be a slight memory overhead, right? or is it some "zero-cost" abstraction?
I am not trying to attack the code for efficiency, just curious about what current implementations can make from this.
Having said that it would've been a very simple extension to make it a recursive algorithm which includes the else case, and arguably would be clearer than the for loop solution.
This makes sense, and I appreciate your reply. I don't think however that it's anything new (or specific to this time period), and even being born means you will constantly be challenged to learn new things, or stay stuck. Also I am not sure about the 'political' sense of this.. I mean, people of different gender identities and beliefs have formed political groups, but I don't think it's a direct connexion.
(I do prefer 'they')
Using 'they' to mean a single person is valid though.