Hackage doesn’t seem to have an easily installable matrix package (hmatrix needs some C libraries), so we’re going to use an Array of Arrays to represent the grid of numbers. We’re going to define a little convenience function to access elements in the 2D array.
at :: Int -> Int -> Array Int (Array Int e) -> e at x y a = a ! y ! x
And the longest common subsequence function itself.
lcs :: Eq a => [a] -> [a] -> [a] lcs xs ys = reverse $ walk imax jmax where imax = length xs jmax = length ys ax = listArray (1, imax) xs ay = listArray (1, jmax) ys ls = listArray (0, jmax) [listArray (0, imax) [lcs' i j | i <- [0..imax]] | j <- [0..jmax]] lcs' 0 _ = 0 lcs' _ 0 = 0 lcs' i j | ax ! i == ay ! j = 1 + at (i-1) (j-1) ls | otherwise = max (at (i-1) j ls) (at i (j-1) ls) walk 0 _ =  walk _ 0 =  walk i j | at (i-1) j ls == at i j ls = walk (i-1) j | at i (j-1) ls < at i j ls = ax ! i : walk i (j-1) | otherwise = walk i (j-1)
And the usual test:
main :: IO () main = print $ lcs "programming" "praxis"
19 lines. Not much of an improvement. More importantly, the speed is far from optimal. The lcs in Data.List.LCS is considerably faster (though considerably longer). If anyone knows a better version, I’m all ears.