Of the three main glues of Haskell (HOFs, the type system, and laziness), laziness is different in that it is not a concrete thing in the language, but is instead related to the way the code will be evaluated in the runtime. Laziness is something that we have to know about rather than something we can always see in the code.
Of course, laziness does show in the language, for example, wherever we want to enforce strict evaluation, as with the
main = do –- lazy IO stream let ios = map putStrLn ["this", "won't", "run"] putStrLn "until ios is 'sequenced'..." sequence_ ios –- perform actions
sequence_ :: [IO ()] -> IO () sequence_ = foldr (>>) (return ())
sequence_ function discards the action results because the ...