Learning Functional Programming in Go

Book description

Function literals, Monads, Lazy evaluation, Currying, and more

About This Book

  • Write concise and maintainable code with streams and high-order functions
  • Understand the benefits of currying your Golang functions
  • Learn the most effective design patterns for functional programming and learn when to apply each of them
  • Build distributed MapReduce solutions using Go

Who This Book Is For

This book is for Golang developers comfortable with OOP and interested in learning how to apply the functional paradigm to create robust and testable apps. Prior programming experience with Go would be helpful, but not mandatory.

What You Will Learn

  • Learn how to compose reliable applications using high-order functions
  • Explore techniques to eliminate side-effects using FP techniques such as currying
  • Use first-class functions to implement pure functions
  • Understand how to implement a lambda expression in Go
  • Compose a working application using the decorator pattern
  • Create faster programs using lazy evaluation
  • Use Go concurrency constructs to compose a functionality pipeline
  • Understand category theory and what it has to do with FP

In Detail

Functional programming is a popular programming paradigm that is used to simplify many tasks and will help you write flexible and succinct code. It allows you to decompose your programs into smaller, highly reusable components, without applying conceptual restraints on how the software should be modularized.

This book bridges the language gap for Golang developers by showing you how to create and consume functional constructs in Golang.

The book is divided into four modules. The first module explains the functional style of programming; pure functional programming (FP), manipulating collections, and using high-order functions. In the second module, you will learn design patterns that you can use to build FP-style applications. In the next module, you will learn FP techniques that you can use to improve your API signatures, to increase performance, and to build better Cloud-native applications. The last module delves into the underpinnings of FP with an introduction to category theory for software developers to give you a real understanding of what pure functional programming is all about, along with applicable code examples.

By the end of the book, you will be adept at building applications the functional way.

Style and approach

This book takes a pragmatic approach and shows you techniques to write better functional constructs in Golang. We’ll also show you how use these concepts to build robust and testable apps.

Table of contents

  1. Title Page
  2. Copyright
    1. Learning Functional Programming in Go
  3. Credits
  4. About the Author
  5. Acknowledgments
  6. About the Reviewer
  7. www.PacktPub.com
    1. Why subscribe?
  8. Customer Feedback
  9. Preface
    1. What this book covers
    2. What you need for this book
    3. Who this book is for
    4. Conventions
    5. Reader feedback
    6. Customer support
      1. Downloading the example code
      2. Downloading the color images of this book
      3. Errata
      4. Piracy
      5. Questions
  10. Pure Functional Programming in Go
    1. Motivation for using FP
    2. Getting the source code
      1. The directory structure of the source files
      2. How to run our first Go application
    3. Imperative versus declarative programming
    4. Pure functions
    5. Fibonacci sequence - a simple recursion and two performance improvements
      1. Memoization
    6. The difference between an anonymous function and a closure
      1. FP using Go's concurrency constructs
    7. Testing FP using test-driven development
      1. A note about paths
      2. How to run our tests
    8. A journey from imperative programming to pure FP and enlightenment
      1. Benchmark test for the imperative SumLoop function
      2. Benchmark test for the SumRecursive function
      3. A time of reckoning
        1. A quick example of a function literal
    9. Summary
  11. Manipulating Collections
    1. Iterating through a collection
    2. Piping Bash commands
    3. Functors
      1. Functions that modify functions
        1. A coding example of functions that modify functions
        2. A visual example of functions that modify functions
          1. Composition in Mindcraft 
      2. Tacit programming
        1. Tacit programming with Unix pipes
        2. Programming CMOS with Unix pipes
        3. Tacit programming with FP
          1. Non-TCO recursive example
          2. TCO recursive example
      3. The importance of recursion
      4. Various intermediate and terminal functions 
      5. Reduce example
      6. Intermediate functions
        1. Common intermediate functions
          1. Map Example
      7. Terminal functions
        1. Common terminal functions
          1. Join example
          2. GroupBy example
          3. Reduce example
    4. Predicates
      1. Reflection
      2. Combinator pattern
    5. Map and filter
    6. Contains
      1. Iterating over a collection of cars
        1. The empty interface
        2. The Contains() method
    7. If Go had generics
      1. Map function
      2. Testing our empty interface-based Map function
    8. Itertools
      1. Go channels used by the New function
      2. Testing itertool's Map function
      3. Testing iterators for element equality
    9. Functional  packages
    10. Another time of reflection
      1. Go is awesome
      2. Go is awesome, but
    11. The cure
      1. Gleam - distributed MapReduce for Golang
        1. LuaJIT's FFI library
        2. Unix pipe tools
      2. Processing Gleam collections
    12. Summary
  12. Using High-Order Functions
    1. Characteristics of FP
      1. Function composition
      2. Monads allow us to chain continuations
      3. Generics
      4. First-class functions
      5. Closure
        1. Dynamically scoped
      6. Pure function
      7. Immuable Data
        1. Persistent data structures for Go
      8. Use of expressions
    2. Sample HOF application
      1. The chapter4 application code
        1. Build and runtime instructions
        2. More application code
        3. The Filter function
          1. Reality check
        4. FilterFunc
          1. Filter function
      2. RESTful resources
        1. Chaining functions
        2. More cars
          1. Reality check
        3. The Map function
          1. Improved performance from the Map function
        4. The Reduce function
        5. More high-order functions
        6. Generators
        7. RESTful server
        8. The GenerateCars function
          1. Currying Goroutine
          2. A closer look at currying
          3. Extending our currying example
          4. Using a WaitGroup variable to manage concurrency
          5. Finishing up the GenerateCars function
        9. Handling concurrency
        10. The final HOF example
    3. Summary
  13. SOLID Design in Go
    1. Why many Gophers eschew Java
      1. More reasons for eschewing Java
      2. Digging deeper into error handling
    2. Software design methodology
      1. Good design
      2. Bad design
        1. Good versus bad design over time
    3. SOLID design principles
      1. Single responsibility principle
        1. Function composition
      2. Open/closed principle
        1. Open / close principle in functional programming
        2. FantasyLand JavaScript specification
          1. Setoid algebra
          2. Ord algebra
        3. The expression problem
      3. Liskov substitution principle
        1. This OOP method stinks
        2. Our FP function smells like roses
        3. In FP, contracts don't lie
        4. Duck typing
        5. What can go wrong with inheritance?
        6. Interface segregation principle
        7. Dependency inversion principle
    4. The big reveal
      1. MapReduce
        1. MapReduce example
      2. What else can Monads do?
    5. Viva La Duck
      1. Pass by value or reference?
      2. Type embedding with Go interfaces
        1. Interface embedding to add minor features
      3. A Go error handling idiom
      4. It's time to run our program
    6. Summary
  14. Adding Functionality with Decoration
    1. Interface composition
      1. Go's complimentary Reader and Writer interfaces
        1. Example usages of the Reader and Writer interfaces
          1. Design with Duck Typing
        2. More reasons to design using interfaces
      2. Using the Reader and Writer interfaces
    2. Decorator pattern
      1. Type hierarchy UML
      2. How Procedural design compares to functional Inversion of Control (IoC)
        1. Procedural design example
        2. Functional IoC example
    3. A decorator implementation
      1. The main.go file
      2. The decorator/simple_log.go file
        1. Example InitLog calls
        2. Back to our main package
        3. Understanding our statistics using the easy-metrics GUI
          1. Quick look at the Dot Init update
          2. Easy-metrics - 1 of 3
      3. The decorator/decorator.go file
        1. A framework to inject dependencies
          1. Wrapping a client request with decorators (in main)
        2. Authorization decorator
        3. Logging decorator
        4. LoadBalancing decorator
          1. Strategy pattern
          2. Inversion of control and dependency injection
          3. Our first failure
          4. Easy metrics - 2 of 3
          5. Groking our trace log file
        5. The rest of the graph
          1. Easy metrics - 3 of 3
        6. Examining the trace log
      4. The decorator/requestor.go file
        1. The job variable declared  in main()
        2. Back to the requestor.go file
        3. Using channels to manage the life cycle
        4. All requests done
        5. Launching our makeRequest goroutine
        6. Our DI framework in action
    4. Summary
  15. Applying FP at the Architectural Level
    1. Application architectures
      1. What is software architecture?
      2. Client-server architecture
      3. Cloud architecture
      4. Why does architecture matter?
    2. The role of systems engineering
      1. Real systems
      2. IT system specialty groups
      3. Systems engineering is lean
      4. Requirements, scope and terms
        1. Defining terms
          1. Software requirements
          2. System
          3. System architecture
          4. System elements
          5. System Boundaries
    3. Managing Complexity
      1. The best tool for the job
      2. Divide and conquer
      3. Designing for state management
        1. Add a microservice
    4. FP influenced architectures
    5. Domain Driven Design
      1. Dependency rule
        1. Cyclic dependency 
          1. Working code
          2. Code with cyclic dependency error
          3. The Golang difference
        2. Solution for cyclic dependencies
    6. Domain Driven Design
      1. Interface-driven development
      2. Hollywood principle
        1. Observer pattern
        2. Dependency injection
    7. A cloud bucket application
      1. Directory structure
        1. main.go
        2. func HandlePanic
      2. Dependency injection
        1. func main()
      3. Layers in the architecture
        1. Domain layer
        2. Use cases layer
          1. Compatible interfaces
        3. Interfaces layer
          1. Why global variables are bad
          2. Format the response
          3. Testing our interfaces
        4. Infrastructure layer
          1. Context object
      4. Benefits of DDD
        1. Adaptability
        2. Sustainability
        3. Testability
        4. Comprehensibility
      5. A solid architectural foundation
    8. FP and Micyoservices
      1. Message passing
        1. All parties must participate
      2. Communication across boundaries
        1. Polyglot Persistence
      3. Lambda architecture
        1. Speed
        2. Batch
        3. Servicing
        4. Next generation big data architecture
      4. CQRS
        1. Benefits of CQRS
      5. Infrastructure architecture
      6. Share nothing architecture
      7. Integrating services
        1. Agreed upon protocol
        2. Circuit breakers
      8. Functional reactive architecture
      9. Go is ideal for building microservices
        1. Size matters
        2. Benefits of gRPC
        3. Who is using Go?
    9. Summary
  16. Functional Parameters
    1. Refactoring long parameter lists
      1. What's wrong with a function signature with more than seven parameters?
      2. Refactoring - the book
      3. Edsger W. Dijkstra says OOP is a bad idea
        1. What else did Edsger W. Dijkstra say?
        2. The underlying OOP problem
        3. OOP inconsistency
        4. Functional programming and cloud computing
          1. A closer look at f(x)
      4. A closer look at refactoring
        1. Passing every parameter a function requires to do its job is not a good idea
        2. Methods can query other objects' methods internally for data required to make decisions
        3. Methods should depend on their host class for needed data
        4. Pass a whole object with required attributes to reduce the number of required parameters
        5. Replace parameter with method technique to reduce the number of required parameters
          1. Before applying Replace Parameter with Method technique
          2. After applying Replace Parameter with Method technique
        6. Use a parameter object when we have unrelated data elements to pass
        7. Long parameter lists will change over time and are inherently difficult to understand
      5. The solution 
        1. Three ways to pass multiple parameters
          1. Simply passing multiple parameters
          2. Passing a configuration object/struct that contains multiple attributes
          3. Partial application
    2. Functional parameters
    3. Contexts
      1. Context limitations
        1. Report example
      2. Writing good code is not unlike a good game of soccer
        1. Functional parameters - Rowe
        2. Report example
      3. A more practical Context use case
        1. src/server/server.go
        2. The src/server/server_options.go file
    4. Summary
  17. Increasing Performance Using Pipelining
    1. Introducing the pipeline pattern
      1. Grep sort example
      2. Pipeline characteristics
      3. Examples
        1. Website order processing
        2. Boss worker pattern
        3. Load balancer
        4. Data flow types
          1. Building blocks
        5. Generalized business application design
    2. Example implementations
      1. Imperative implementation
        1. Decrypt, authenticate, charge flow diagram
      2. Concurrent implementation
      3. Buffered implementation
        1. Leverage all CPU cores
      4. Improved implementation
        1. Imports
        2. BuildPipeline
        3. Immediately executable Goroutine
        4. Receive order
        5. Filterer interface
        6. A Filterer object
        7. Authenticate filter
        8. Decrypt filter
          1. Complete processing
          2. The ChargeCard helper function
        9. Charge filter
        10. The encrypt and decrypt helper functions
      5. Testing how the application handles invalid data
        1. Invalid credit card cipher text
        2. Invalid password
        3. Changing the order of authenticate and decrypt filters
        4. Attempting to charge before decrypting credit card number and authentication
        5. Attempting to charge before authentication
      6. Further reading
    3. Summary
  18. Functors, Monoids, and Generics
    1. Understanding functors
      1. An imperative versus pure FP example
        1. What did that Map function do for us?  
        2. What possible benefits can this afford us?
      2. A magical structure
        1. Color blocks functor
        2. Fingers times 10 functor
      3. Definition of a functor in Haskell
      4. Kinds of types
        1. Maybe
      5. Polymorphism at a higher level
      6. No Generics results in a lot of boilerplate code 
    2. Solve lack of generics with metaprogramming
    3. Generics code generation tool
      1. The clipperhouse/gen tool
        1. If Go supported generics
          1. Adding new methods
          2. Defining a filter function 
      2. Nums revisited
        1. The slice typewriter
          1. Aggregate[T]
    4. Generics implementation options
      1. We used the gen tool
    5. The shape of a functor
      1. Functor implementation
        1. ints functor
      2. Functor definition
        1. Identity operation
    6. Composition operation
      1. Composition example in Go
      2. Haskell version of compose
      3. (g.f)(x) = g(f(x)) composition in Go
        1. The (g.f)(x) = g(f(x)) implementation
        2. A note about composition naming conventions in Go
      4. The directions of the arrows are significant
        1. EmphasizeHumanize ordered incorrectly
      5. Function composition is associative
    7. Functional composition in the context of a legal obligation
      1. Decisions determine state transitions
      2. Category theory review
        1. Categorical rules
        2. Results oriented
      3. The forgetful functor and the law
        1. The rule of law
        2. Lucy’s forgetful functor
        3. Larry’s forgetful functor
    8. Build a 12-hour clock functor
      1. Clock functor helpers
        1. The Unit function
        2. The AmPmMapper function
        3. The AmHoursFn helper
        4. The String helper function
        5. main.go
        6. Terminal output log
        7. Functor summary
    9. The car functor
      1. The functor package
      2. main.go
        1. Compare one line of FP to a bunch of imperative lines
        2. Car functor terminal session
    10. Monoids
      1. Monoid rules
        1. Closure rule
          1. Closure rule examples
          2. Closure axiom
        2. Associativity rule
        3. Identity rule
          1. Identity rule examples
          2. An identity of 0
      2. Writing a reduction function
      3. A semigroup is a missing neutral value
        1. Converting binary operations into operations that work on lists
        2. Using monoids with divide and conquer algorithms
      4. Referential transparency
      5. Handling no data
      6. More examples of monoids
      7. What are not monoids?
    11. Monoid examples
      1. Name monoid
        1. Name monoid terminal session
          1. Int slice monoid
          2. Lineitem slice monoid
          3. Int slice monoid terminal session
    12. Summary
  19. Monads, Type Classes, and Generics
    1. Mother Teresa Monad
      1. The bind operation
      2. The lift operation
      3. Monadic functions
        1. Basic monadic functions
      4. Monadic list functions
    2. Monadic workflow implementation
      1. Lambda calculus
    3. Y-Combinator
      1. The Y in Y-Combinator
      2. How the Y-Combinator works
        1. The Lexical Workflow solution
      3. Is our ProcessCar method idomatic Go code?  
        1. The non idiomatic parts
        2. The idiomatic parts
    4. An alternative workflow option
    5. Business use case scenarios
    6. Y-Combinator re-examined
      1. What is tail recursion?
      2. Big-Oh notation
        1. InternationalizatioN (I18N) package
    7. Type classes
      1. Base class definitions
        1. Int base class
        2. String base class
        3. Our main.go file
        4. Sum parent type class
        5. Sum base classes
    8. Generics revisited
      1. Impact of Golang
        1. Personal opinion
    9. Summary
      1. Where to go from here
  20. Category Theory That Applies
    1. Our goal
      1. Break it down
      2. Algebra and the unknown
      3. Real-world application of algebra
        1. Linear equation and the law of demand
        2. Quadratic equations all around us
        3. Function composition with linear and quadratic functions
        4. More examples of quadratic equations
          1. The golden ratio
      4. Basic laws of algebra
      5. Correspondence in mathematics
    2. Proof theory
      1. Logical connectives
        1. Logical inconsistency
          1. Partial function
      2. Truth table
        1. Conditional propositions
        2. Logical equivalence
        3. Converse of a conditional proposition
          1. Order matters
    3. The Curry Howard isomorphism
      1. Examples of propositions
      2. Not propositions
      3. Lambda calculus
        1. Why so formal?
          1. The importance of protocol
    4. Historical Events in Functional Programming
      1. George Boole (1815 - 1864)
      2. Augustus De Morgan (1806 - 1871)
      3. Friedrich Ludwig Gottlob Frege (1848 – 1925)
        1. Modus Ponens
      4. Charles Lutwidge Dodgson (1832 –1898)
      5. Alfred Whitehead and Bertrand Russell (1903)
      6. Moses Schonfinkel (1889–1942)
      7. Haskell Curry - 1927
      8. Gerhard Gentzen (1936)
      9. Alonzo Church (1930, 1940)
      10. Alan Turing (1950)
      11. MacLane and Eilenberg (1945)
      12. John McCarthy (1950)
      13. Curry-Howard-Lambek Correspondence (1969)
      14. Roger Godement (1958)
      15. Moggi, Wadler, Jones (1991)
      16. Gibbons, Oliveira (2006)
      17. The history of FP in a nutshell
        1. Where to go from here
    5. Programming language categories
      1. A declarative example
      2. An imperative example
      3. An OOP example
      4. Venn diagram of four programming paradigms
      5. Five generations of languages
      6. The Forth language
      7. The LINQ language
      8. Type systems
    6. The Lambda Calculus
      1. Lambda Expressions
        1. Anonymous function example and type inference
        2. Lambda expression ingredients
          1. Visualizing a lambda expression
          2. A Lambda calculus is like chocolate milk
        3. Lambda examples in other languages
          1. JavaScript
          2. JavaScript (ES6)
        4. Ruby
    7. The importance of Type systems to FP
      1. Static versus dynamic typing
      2. Type inference
      3. Haskell
        1. Type classes in Haskell
    8. Domains, codomains, and morphisms
    9. Set theory symbols
    10. Category theory
      1. Algebra of functions
        1. Abstract functions
        2. Official definition of a function
        3. Intuitive definition of a function
        4. Function composition with sets
          1. Composition operation example using travel expenses
      2. A Category
        1. Category axioms
        2. Category laws
        3. More rules
        4. More examples
          1. Invalid categories
    11. Morphisms
      1. The behaviors of morphisms
        1. Composition operation
        2. Identity operation
      2. Law of associativity
        1. Only concerned with morphisms
          1. Interface-driven development
      3. More morphisms
      4. A review of Category theory
      5. Even more correspondence
      6. Table of morphisms
        1. Morphism examples
        2. Modens ponens
          1. Type theory version
          2. Logic version
        3. Correspondence between logic and type theory
        4. Cartesian closed category 
        5. Unit type
    12. Homomorphism
      1. Homomorphisms preserve correspondence
      2. Homomorphic encryption
        1. An example of homomorphic encryption
          1. Lesson learned
      3. Isomorphism
        1. Injective morphism
        2. Surjective morphism
        3. Endomorphism
        4. SemiGroup homomorphism
        5. SemiGroup Homomorphism Algebra
      4. Homomorphism table
        1. Car crash analogy
    13. Composable concurrency
      1. Finite state machines
    14. Graph Database Example
    15. Using mathematics and category theory to gain understanding
      1. Laws of exponentials for building a lambda expression
        1. Table legend 
        2. For the top right law...
      2. Sums and products
        1. Isomorphic equations
    16. Fun with Sums, Products, Exponents and Types
    17. Big data, knowledge-driven development, and data visualization
      1. Data visualization
    18. Summary
  21. Miscellaneous Information and How-Tos
    1. How to build and run Go projects
      1. TL;DR
      2. Development workflow
      3. Dot init features and benefits
        1. Aliases available
        2. Functions available
      4. Motivation for using goenv
      5. Motivation for using the init script
      6. Ways to manage Go dependencies
        1. The go get tool
        2. The Godep tool
        3. Vendoring in Go
        4. Glide - the modern package manager
      7. Each dot init step in detail
        1. The cd command to project root directory
          1. Using homebrew to install Go
        2. Examining the initial directory structure and files
        3. The init script contents
        4. Running the init script
        5. Re-examining the initial directory structure and files
        6. The goenv shows what's been updated
        7. Running glide-update to get third-party dependency files
      8. Adding standard library imports
        1. The Go standard library 
      9. Adding third-party imports
        1. Importing statement referencing  go_utils
    2. Development workflow summary
      1. Troubleshooting dot init
    3. A note about Go Dependency Management
    4. A conversation - Java developer, idiomatic Go developer, FP developer
    5. How to propose changes to Go
      1. The first step - search specs
      2. Second step - Google search
      3. The official Golang change proposal process
        1. Search for existing issues
        2. Reading existing proposals
        3. Adding a comment to the existing TCO proposal
      4. Creating a new proposal
      5. Creating a design document
      6. Sending an email to notify the golang-dev group
      7. An example proposal
      8. Monitoring a proposal until the resolution is reached
    6. FP resources
    7. Minggatu - Catalan number
      1. An explanation and call to action

Product information

  • Title: Learning Functional Programming in Go
  • Author(s): Lex Sheehan
  • Release date: November 2017
  • Publisher(s): Packt Publishing
  • ISBN: 9781787281394