Skip to content

0006: Email Tutorials Haskell For Beginners ‐ Defining Simple Functions in Haskell (the basics)

Bernard Sibanda edited this page Dec 16, 2025 · 4 revisions

LigerLearn Video 6

📑 Table of Contents

  • 6.1. Function Type Signatures: The General Template
  • 6.2. Bindings: Connecting Names, Parameters, and Logic
  • 6.3. A First Example: Adding Two Int Values
  • 6.4. Calling Functions with Juxtaposition (No Brackets, No Commas)
  • 6.5. How Haskell’s Style Differs from C and Java
  • 6.6. A Second Example: Adding Three Double Values
  • 6.7. When and Why You Need Brackets
  • 6.8. Ignoring Unused Parameters with _
  • 6.9. Glossary of Terms for This Lesson

6.1. Function Type Signatures: The General Template

In Haskell, functions—just like simple values—always have type signatures. A type signature describes what types of inputs a function takes and what type of output it produces. The general template presented in this lesson starts with the function name, followed by a double colon. After the double colon, you list the type of the first parameter, then an arrow (spelled using a dash and greater-than sign), then the type of the next parameter, and so on, until you reach the final arrow and the return type of the function. Every function has at least one parameter and therefore at least one arrow, and the last type in the chain is always the result type. Reading these signatures becomes more natural with practice, and they are one of the most important tools for understanding and reasoning about Haskell code.

6.2. Bindings: Connecting Names, Parameters, and Logic

Every function in Haskell has at least one binding. A binding is the line of code where you give the function its parameter names and define what it actually does. Later in the course, when pattern matching is introduced, you will see examples of functions with multiple bindings, but for now each function has a single binding. The template for a binding mirrors the type signature: for each parameter type that appears in the type signature, you must provide a parameter name in the binding. These parameter names follow the function name on the left-hand side and are separated from each other by single spaces. This style of writing parameters next to each other with spaces is known as juxtaposition. On the right-hand side of the binding, you write the function body—the expression that describes how the result is computed from the parameters.

6.3. A First Example: Adding Two Int Values

The lesson presents an example function that adds two integers. Its type signature states that the function takes two values of type Int and returns an Int. From this alone, you know there must be two parameters in the binding. On the next line, you see the binding itself: the function name followed by two parameter names, often something simple like a and b, each separated by a space. The body of the function then uses Haskell’s built-in addition operator to add a and b together. This example demonstrates how the type signature and binding relate: the signature tells you the types and number of parameters; the binding gives those parameters names and defines the logic that produces the result.

6.4. Calling Functions with Juxtaposition (No Brackets, No Commas)

To call the function, you again use juxtaposition: you write the function name followed by the arguments, each separated by a space. For instance, if you call the function with the values 202 and 6, then a becomes 202 and b becomes 6, and the result is 208. A second call with 89 and 32 results in 121. Notice that you do not use brackets or commas around the arguments. This is a key difference from many other languages. In Haskell, simply placing values next to each other with spaces is both how you define parameter lists in bindings and how you supply arguments in calls. This concise style is standard in functional programming and is part of what makes Haskell code both compact and expressive.

6.5. How Haskell’s Style Differs from C and Java

If you are coming to Haskell from languages like C or Java, several aspects of function definitions may feel unfamiliar at first. One difference is that Haskell places the entire type signature on its own line, separate from the binding. In other languages, types are typically attached to each parameter and a return type is written before the function name. Another difference is that Haskell does not require parentheses and commas for argument lists in the same way; instead, it relies on whitespace and juxtaposition. While this style is different, it is not inherently difficult. Once you know that the arrow represents the flow from parameter types to return type, and that spaces represent function application, reading and writing Haskell function definitions becomes straightforward.

6.6. A Second Example: Adding Three Double Values

The lesson then introduces another example: a function called something like addThreeDoubles. Its type signature shows that it takes three parameters of type Double and returns a Double. From the signature, it is clear that the binding should include three parameter names following the function name. In the binding, you see the function name and then three parameter names—again separated by spaces—and the body simply adds these parameters together. Calling this function follows the same pattern as before: you write the function name followed by three numeric values separated by spaces. This second example reinforces the idea that the type signature and binding must match in the number and types of parameters, and that function calls mirror the binding structure.

6.7. When and Why You Need Brackets

Although Haskell normally does not require brackets for function calls, there are cases where brackets become important to remove ambiguity. The lesson provides an example where the result of a function call is itself used as an argument to another call of the same function. Suppose you have a function that adds two integers and you want to use the result of one call as the second argument to another call. In that case, you must put the inner function call in brackets to ensure the compiler understands that it should be evaluated first and treated as a single argument. Without brackets, Haskell would interpret the expression as a function being applied to too many arguments, resulting in a compile-time error. Thus, brackets are reserved for grouping and clarifying complex expressions rather than being required by default for every function call.

6.8. Ignoring Unused Parameters with _

Another important detail covered in this lesson is how to handle unused parameters. Sometimes a function receives a parameter that it does not actually need in its body. In such cases, rather than inventing a variable name that is never used, you can replace that name with an underscore (_). For example, you might have a function that takes a three-element tuple but only ever returns the first element. There is no need to name the second and third elements. Using underscores for them indicates clearly that they are intentionally ignored. This not only avoids warnings about unused variables but also improves readability: when you see an underscore in a pattern, you immediately know that the value in that position is not relevant to the function’s logic. You still call the function in the usual way; the underscore only affects the binding, not the way the function is used.

6.9. Glossary of Terms for This Lesson

  • Type signature A declaration that specifies the types of a function’s parameters and its return value. It appears on its own line, using the double colon followed by parameter types separated by arrows and ending with the result type.

  • Binding The line (or lines) that define the function’s parameters and body. It contains the function name, the parameter names written with spaces, an equals sign, and the expression that computes the result.

  • Parameter A named input to a function. Each parameter has a type indicated in the type signature and a name used in the binding and function body.

  • Return type The type that appears after the final arrow in a function’s type signature. It describes the kind of value the function produces when called.

  • Arrow (->) Written as a dash followed by a greater-than sign, it separates types in a function type signature. Each arrow can be read as “takes” or “returns,” with the last type representing the function’s result.

  • Juxtaposition The style of writing function names and parameters or arguments simply next to each other with spaces, without brackets or commas. In Haskell, juxtaposition is how you both define and call functions.

  • Int A basic integer type used for whole numbers. In the examples, functions operate on Int values to produce integer results.

  • Double A floating-point type used for real numbers with fractional parts. In the lesson’s example, a function sums three Double values.

  • Brackets (parentheses) Used in Haskell to group expressions and remove ambiguity, especially when one function call is used as an argument to another. They are not required for ordinary function calls with simple arguments.

  • Underscore (_) A special placeholder used in patterns to indicate that a parameter or part of a value is intentionally ignored. It improves clarity when certain inputs are not needed in the function body.

Glossary of Terms (LigerLearn Video 6)

  • Function — A definition that takes input(s) and produces an output.
  • Type signature — A declaration that states a function’s input types and output type.
  • Double colon (::) — Symbol that introduces a type signature (e.g., f :: Int -> Int).
  • Parameter type — The type of an input in a function signature.
  • Return type / Result type — The final type in a function signature; what the function produces.
  • Arrow (->) — Separates types in a function signature; read as “takes … and returns …”.
  • Template (function signature)name :: t1 -> t2 -> ... -> result.
  • Binding — The line that gives parameter names and defines the function body.
  • Left-hand side (LHS) — The part of a binding with the function name and parameter names.
  • Right-hand side (RHS) — The expression after = that computes the result.
  • Equals sign (=) — Separates the LHS (name/parameters) from the RHS (body).
  • Parameter — A named input variable in the binding (e.g., a b).
  • Argument — The actual value you pass when calling the function (e.g., add 202 6).
  • Function call / Function application — Using a function with arguments to get a result.
  • Juxtaposition — Writing function name and arguments next to each other with spaces (no commas).
  • Whitespace significance — Spaces help define structure and function application in Haskell.
  • Int — Integer type for whole numbers.
  • Double — Floating-point type for decimal numbers.
  • Addition operator (+) — Built-in operator that adds two numeric values.
  • Brackets / Parentheses ((...)) — Used to group expressions and remove ambiguity.
  • Grouping — Forcing part of an expression to be treated as a single unit (often via parentheses).
  • Ambiguity — When code could be interpreted in more than one way without grouping.
  • Too many arguments error — Common error when you forget parentheses and Haskell parses extra applications.
  • Compile-time error — An error detected before running the program.
  • C / Java style (contrast) — Languages that typically use parentheses/commas for arguments and types inline.
  • Unused parameter — A parameter that is accepted but not referenced in the function body.
  • Underscore (_) — A placeholder meaning “ignore this value” in a binding/pattern.
  • Warning (unused variable) — A compiler message when you name something but never use it.

Quizz & Progress Badge NFT

Clone this wiki locally