Upon reading this Python question and proposing a solution, I tried to solve the same challenge in Haskell.
I've come up with the code below, which seems to work. However, since I'm pretty new to this language, I'd like some help in understand whether the code is good performancewise.
lswrc :: String -> String
lswrc s = reverse $ fst $ foldl' step ("","") s
where
step ("","") c = ([c],[c])
step (maxSubstr,current) c
| c `elem` current = step (maxSubstr,init current) c
| otherwise = let candidate = (c:current)
longerThan = (>) `on` length
newMaxSubstr = if maxSubstr `longerThan` candidate
then maxSubstr
else candidate
in (newMaxSubstr, candidate)
Some points I think could be better than they are
- I carry on a pair of strings (the longest tracked, and the current candidate) but I only need the former; thinking procedurally, there's no way to escape this, but maybe FP allows another approach?
- I construct
(c:current)
but I use it only in theelse
; I could make a more complicatedlongerThan
to add 1 to the lenght of its second argument, so that I can apply it tomaxSubstr
andcurrent
, and construct(c:current)
in theelse
, without even giving it a name. - I drop the last element of
current
whenc
is in thecurrent
string, because I'm piling up the strings with:
; I could instead pattern match when checkingc
against the string (as inc `elem` current@(a:as)
), but then when adding the new character I should docurrent ++ [c]
, which I know is not as performant asc:current
. - I use
foldl'
(as I knowfoldl
doesn't really make sense);foldr
could be an alternative, but since I don't see how laziness enters this problem, I can't tell which one would be better.