= functions that take one or more functions as arguments or return a function as a result.
packagemainimport ("fmt")funcpower(fn func(int) int) func(int) int { // <--- high-order functionreturnfunc(x int) int {returnfn(x) }}funcsquare(x int) int {return x * x}funccube(x int) int {return x * x * x}funcmain() { squareFunc :=power(square) cubeFunc :=power(cube) fmt.Println(squareFunc(2)) // Output: 4 fmt.Println(cubeFunc(2)) // Output: 8}
Anonymous functions/Closures/Lambda Functions
= functions that are defined and called in the same place, without a name. They retain bindings to variables defined outside the body of the closure.
packagemainimport"fmt"funcmain() { sum :=func(a, b, c int) int {return a + b + c }(3, 5, 7) fmt.Println("5+3+7 =", sum)}
Monads
= design pattern that allows us to chain operations together in a pipeline, while abstracting away the details of how the operations are performed. Has 3 components:
Type Constructor (T): A type that represents a computational context. It wraps a value and provides a way to apply functions to that value while preserving the context.
Unit Function (unit or return): A function that takes a value and wraps it in the monadic context, creating a new instance of the monad.
Bind Function (flatMap, chain, >>=): A function that takes a monad and a function that maps a value to a new monad. It applies the function to the value inside the monad and returns a new monad.
packagemainimport ("errors""fmt")// Result represents a monad-like type that can either hold a value or an error.typeResultstruct { value int err error}// Unit function wraps a value in the Result monad.funcUnit(val int) Result {returnResult{value: val}}// Bind function applies a function to the value inside the Result monad.func (r Result) Bind(f func(int) Result) Result {if r.err !=nil {return r }returnf(r.value)}// Example functions that work with Result monads.funcaddOne(x int) Result {returnUnit(x +1)}funcdivideBy(x int, y int) Result {if y ==0 {returnResult{err: errors.New("division by zero")} }returnUnit(x / y)}funcmain() {// Using Result monad to sequence computations. result :=Unit(10).Bind(addOne).Bind(func(x int) Result {returndivideBy(x, 5) })if result.err !=nil { fmt.Println("Error:", result.err) } else { fmt.Println("Result:", result.value) }}
Functors
= objects or data structures that can be mapped over, meaning you can apply a function to each element within the functor.
= superclass of a monad, which means that all monads are functors as well.
= design pattern that represents a container or structure that can be mapped over. In functional programming, a functor is often used to apply a function to each element of a collection and return a new collection with the transformed elements.
packagemainimport"fmt"// IntList is a custom functor-like type representing a list of integers.typeIntList []int// Map applies a given function to each element in the IntList and returns a new IntList.func (il IntList) Map(fn func(int) int) IntList { result :=make(IntList, len(il))for i, v :=range il { result[i] =fn(v) }return result}funcmain() {// Creating an IntList. list :=IntList{1, 2, 3, 4, 5}// Define a function to square each element. square :=func(x int) int {return x * x }// Using the Map method to apply the square function to each element. squaredList := list.Map(square)// Printing the squared list. fmt.Println(squaredList) // Output: [1 4 9 16 25]}
Monoids
= data types that have two key properties: associativity and an identity element.
Associativity: For all values a, b, and c of the same type, (a mappend b) mappend c should be equal to a mappend (b mappend c), where mappend represents the operation.
Identity Element: There exists an element (usually denoted as mempty) such that for any value a of the same type, mempty mappend a is equal to a and a mappend mempty is equal to a.
packagemainimport"fmt"// IntMonoid is a custom monoid-like type representing integers with addition as the operation.typeIntMonoidint// Mappend defines the addition operation for IntMonoid.func (a IntMonoid) Mappend(b IntMonoid) IntMonoid {return a + b}// Mempty represents the identity element for IntMonoid, which is 0 for addition.func (IntMonoid) Mempty() IntMonoid {return0}funcmain() {// Create instances of IntMonoid. x :=IntMonoid(5) y :=IntMonoid(10)// Use the Mappend method to combine values. result := x.Mappend(y)// Print the result. fmt.Println(result) // Output: 15}