A function transforms input data into an output value. In F#, functions are the main unit of behavior: model application state as data, then build functions that validate, transform, and eventually emit results such as JSON, files, or messages. A purchase flow, for example, can validate a request, turn it into an invoice, and email that invoice as separate steps. section 1.5.5
Define functions with let. The same declaration pattern also binds ordinary values, because functions are values too: they can be named, passed as arguments, and assembled with other functions. Indentation defines the function body, while type inference usually determines argument and result types without annotations. section 3.1.1 section 3.1.2
Define and call a function
let greetPerson name age = $"Hello, {name}. You are {age} years old" greetPerson "Fred" 21 Defining the function loads it into F# Interactive; calling it supplies values and produces the greeting. Change the arguments and run it again to experiment with the result. section 2.5.5
Prefer small functions that do one job, then compose them into larger behavior. This keeps calculation separate from output: a function can calculate an age description, while another prints it. The calculation can then be reused for console output, files, or tests without bringing printing along with it. section 2.1.2 section 4.1.5
IEnumerable<int> SquareNumbers(IEnumerable<int> numbers) {
// implementation of square elided...
}
IEnumerable<int> GetEvenNumbersThenSquare(IEnumerable<int> numbers) {
return SquareNumbers(GetEvenNumbers(numbers)) #1
}
let squareNumbers = Seq.map (fun x -> x * x)
let getEvenNumbersThenSquare = getEvenNumbers >> squareNumbers #2
Compare nested method calls with composition: getEvenNumbers feeds directly into squareNumbers, making the reusable transformation sequence explicit. section 2.1.2
F# functions always have one input and one output. A function with no meaningful input or output uses unit (). Apparent multi-argument functions are curried: supplying the first argument returns a function waiting for the next. This supports partial application, such as fixing an initial value before supplying the rest later. section 6.1.1 section 6.4
Listing 6.2 Calling an F# function
let add (firstNumber:int) (secondNumber:int) = #1
firstNumber + secondNumber
let addFive = add 5 #2
let fifteen = addFive 10 #3
Calling add with 5 creates addFive, a new function that accepts the remaining number; calling it with 10 yields 15. section 6.1.1
Organize behavior in modules that operate on records, tuples, and unions instead of fusing mutable state and methods into classes. A basket, for instance, can be immutable data with AddItem, Clear, and Checkout functions that return an updated basket. This separation makes behavior easier to create, test, maintain, and change independently of the data shape. section 2.1.3 section 10.1.2
For testable code, favor functions that take all required data as arguments and return results rather than changing hidden state. Tests can then arrange input, call the function, and assert the output. Test small, lower-level functions or groups first when possible, since they usually isolate more of the algorithmic logic. section 14.3.1 section 14.3.3
Functions work alongside the .NET ecosystem. F# can call C# classes and methods when needed, while F# functions in modules appear as methods to C# callers; partially applied functions are exposed with normal C# method arguments. section 11.1.1 section 11.2.1



















