Function Factory
Books are made out of sentences that build on each other, melodies are made out of phrases that develop a theme, and Haskell programs are made out of functions that call each other. In other languages, we spend considerable time modeling objects that mutate each other to produce a result. In Haskell, a computation is a chain of function calls. Writing functions is so routine in Haskell that the language provides four distinct ways to define them.
We've already seen one way to define a function: through a named definition. For example, this Haskell code defines a named function that produces a diminutive form of a regular Spanish noun or adjective:
diminutive :: String -> String
diminutive word = stem ++ "it" ++ gender
where
stem = init word -- discard last letter
gender = last word -- extract last letter, a or o
diminutive :: String -> String diminutive word = stem ++ "it" ++ gender where stem = init word -- discard last letter gender = last word -- extract last letter, a or o
These calls illustrate its use:
diminutive "hermano" -- yields "hermanito", little brother
diminutive "abuela" -- yields "abuelita", little grandma
diminutive "mesa" -- yields "mesita", little table
diminutive "hermano" -- yields "hermanito", little brother diminutive "abuela" -- yields "abuelita", little grandma diminutive "mesa" -- yields "mesita", little table
The named definition syntax is the most verbose of the four ways to define functions. In this chapter, you will learn three shorter ways. Additionally, you will explore several other features of functions that reduce the labor of writing Haskell programs. By the end of the chapter, you will be able to answer the following questions:
- How do lambdas, partial application, and composition—the remaining three ways to define functions—ease the task of programming?
- How is pattern matching and destructuring used to simplify conditional logic and compound data structures?
- How are map, filter, fold, and other higher-order functions implemented and used?
- What should happen when a function has free variables but it outlives the scope in which the variables are bound? Should that even be legal?
Haskell is a function factory in which functions are defined or called on nearly every keystroke. Because of its dogged commitment to functions, Haskell's developers have pioneered or popularized a number of features that lighten the burden of defining new functions, and its influence has been felt in other languages. Newer languages like Rust started with these features, while older languages like Java adapted to support them.