First, I like the explicit statement of the type signature. That's a good habit to get into, and makes it easier to capitalise on perhaps the greatest strength of using Haskell which is all the compile time checking. The provided signature is as general as it can be for lists.
Second, the single element base case is written cleanly and correctly.
The recursive case has room for a bit of picking apart. It is convention to use pattern matching syntax x:xs
(or x1:x2:xs
) for list recursive functions. As well as being cleaner to read, the behaviour is slightly different in that it can work out the first, second, and remainder of the list in a single pass without having to separately call !!
twice and drop
once.
foldl1' f (x1:x2:xs) = foldl1' f ((f x1 x2):xs)
One other improvement that I would suggest, taken directly from the prelude function by the same name, is explicitely handling the failure case when provided with an empty list. For comparison the inbuilt function produces an exception:
foldl1 (+) []
*** Exception: Prelude.foldl1: empty list