Let's take a look at the function maximum
from the Standard Haskell Prelude:
maximum :: (Ord a) => [a] -> a
maximum [] = error "Prelude.maximum: empty list"
maximum xs = foldl1 max xs
It’s pretty clear what this function does from its name and the type signature. But the implementation, although short, is not trivial.
Let's reduce an expression to understand this function better:
Example.hs
with the following content:{-# OPTIONS -XNoImplicitPrelude #-}
module Example where
import SteppablePrelude
result = maximum [1, 2, 3]
To prevent naming conflicts, the automatic import of the Standard Haskell Prelude has to be disabled with the Option -XNoImplicitPrelude
.
substep step -p Example.hs -c True -f result -v 1
You get this output:
**Reduction of example**
maximum [1, 2, 3]
{- skipping 3 substeps -}
{- Replace with matching pattern -}
foldl1 (max) [1, 2, 3]
{- skipping 4 substeps -}
{- Replace with matching pattern -}
foldl (max) 1 [2, 3]
{- skipping 4 substeps -}
{- Replace with matching pattern -}
foldl (max) (max 1 2) [3]
{- skipping 4 substeps -}
{- Replace with matching pattern -}
foldl (max) (max (max 1 2) 3) []
{- skipping 4 substeps -}
{- Replace with matching pattern -}
max (max 1 2) 3
{- (Strict) reduce application argument -> Evaluate unsteppable function/operator max -}
max 2 3
{- Evaluate unsteppable function/operator max -}
3
{- reduction completed successfully -}
Now, the behavior of the maximum
function (as well as the foldl
function) should make much more sense.