I\'m trying to learn coding in Haskell.
I started with an easy example \"the product of a list\".
product :: [Integer] -> Integer
product [] = 1
You can use a fold:
product :: Num a => [a] -> a
product xs = foldl (*) 1 xs
This can also be done strictly with foldl'
or foldr
, the differences mostly are performance, but since you're just starting out I'll skip that lecture this time.
So what does a fold do? Let's start with the basic definition of foldl
:
foldl :: (a -> b -> a) -> a -> [b] -> a
foldl f acc [] = acc
foldl f acc (x:xs) = foldl f (f acc x) xs
What this does is takes a function f :: a -> b -> a
which takes an accumulator and an additional value, which is fed to it from the list of values. It iteratively applies this function, generating a new accumulator at each step, until it runs out of values in the list. For (*)
it looks something like
> foldl (*) 1 [1, 2, 3, 4]
| foldl (*) (1 * 1) [2, 3, 4] = foldl (*) 1 [2, 3, 4]
| foldl (*) (1 * 2) [3, 4] = foldl (*) 2 [3, 4]
| foldl (*) (2 * 3) [4] = foldl (*) 6 [4]
| foldl (*) (6 * 4) [] = foldl (*) 24 []
| 24
I should add that this isn't exactly how it's performed in memory unless you use foldl'
, which is the strict version, but it's easier to follow this way.
Well in Haskell we don't have loops so iterative is relative, but here's the "functional iteration approach"
product = foldl' (*) 1
folds are the equivalent of loops in imperative languages. foldl'
in particular is tail recursive and strict so it will run in constant space, similar to a loop.
If we were to write it explicitly
product = go 1
where go accum (x:xs) = go (accum * x) xs
go accum _ = accum -- Subtle performances
-- differences with strictness
This is still recursive, but will compile to similar assembly.