I am having some difficulty with a program I've written using Haskell. The idea behind it is to recursively find the shortest list in a list of lists and return that. I've managed to write the program okay but I can't seem to figure out what I've done wrong in it. These are the errors that I get when I try to compile it:
Here is the code I'm using:
shortest :: [[a]] -> [a]
shortest [] = []
shortest [y] = y
shortest (x:y:list)
| length x > length y = shortest y:[list]
| otherwise = shortest x:[list]
If anyone could give me any pointers as to where I'm going wrong it would be much appreciated!
list
is already the tail of your input; you don't need to (nor should you) wrap it in another list.
shortest (x:y:list) = shortest $ (if length x > length y then y else x) : list
At each step, it's just a question of which element, x
or y
, you remove from the input to the recursive call.
Another way, which doesn't require two base cases, is to just compare the head of the list to the result of recursing on the tail.
shortest [] = []
shortest (x:xs) = let s = shortest xs
in if length s < length x then s else x
Finally, tuples compare lexicographically, so you can also dispense with explicit recursion by tagging each list with its length, finding the smallest tagged value, then extracting the original list.
shortest = snd . minimum . map (\x -> (length x, x))
Using Control.Arrow
, you can write the argument to map
as (length &&& id)
.
Caveat for the last approach: since lists also compare lexicographically, the final result if you have multiple lists with the shortest length will depend on how the list values themselves compare. The first two examples, by contrast, are stable; the first such shortest list is returned.
Daniel Wagner points out a better solution for using minimum
, which is to wrap each element in an Arg
value which lets two lists be compared solely on their lengths, without considering the lists' contents.
import Data.Semigroup
shortest xs = x where Arg _ x = minimum [Arg (length x) x | x <- xs]
Arg
is basically a 2-element product type which only uses the first element for its Ord
instance, unlike (,)
which uses both.