This document discusses algebraic data types and functional programming concepts in C++. It begins by defining algebraic data types like unit, product, and sum types using common notation. It then provides examples of implementing these types in C++ using techniques like boost variants and recursive types. The document also discusses implementing functional concepts in C++ like laziness using function objects, currying using the gfp library, and generic programming using type classes. It concludes by introducing category theory concepts and how they relate to functional programming.
1. Functional Programming Algebraic Data Types
Functional Programming (in C++) What? Why? How (in C++)?
unit, primitive type, one value, denoted ()
- Algebraic Data Types : (), :=, : =, ,
⊕⊗
- Functions : a (b c)
→→
con 20 - Generic Programming
ost : (c◄C) → c int
→
bo
David Sankel 10 - Category Theory
: monoid, monad, etc.
Sankel Software 1 2 3
Algebraic Data Types
unit, primitive type, one value, denoted ()
+
product, binary type operation,
denoted a b, “a and b”, one of each
⊗
4
2. Algebraic Data Types Examples: Examples:
unit, (), one value true : = () Z : = ()
product, a b, “a and b”
⊗ false : = () N := Z ⊕ N
sum, a b, “a or b”
⊕ bool := true ⊕ false
is the same as, a := b Z is implemented with unit.
is implemented with, a : = b true is implemented with unit. A N value is the same as a Z value or an N
false is implemented with unit. value.
A bool value is the same as a true value or
a false value.
7 8 9
Examples: Type Functions Type Functions
Z : = () Add parameter on left side of : = or := [] : = ()
N := Z ⊕ N symbol that can be used on the right. L a := [] ⊗ ⊕ (a L a)
[] : = () Say ai is a value of type a. and e is the
z Z
∈ L a := [] ⊗ ⊕(a L a)
N0 = (0,z) value of type [].
A value of “L of a” is either a
N1 = (1,N0) = (1,(0,z)) (0,e)
(1,(ai,(0,e))
N2 = (1,N1) = (1,(1,(0,z))) value of [] or (a value of a and a value of
10
“L of a”). 11
(1,(aj,(1,(ai,(0,e))
12
3. Type Functions Algebraic Data Types Algebraic Data Types (in C++!)
T a : = (T a ⊗ T a) ⊕ a - Abstract Our critera for functional concepts in C++
- No (minimal) syntax sugar, it scares
Binary tree with values of type 'a' at the - Simple ((), :=, : =, ,
⊕⊗ ) away the new bees.
leaves.
- Powerful - Mixes well with typical C++.
- ... - No copycatting other
languages and their limitations..
13 14 15
Algebraic Data Types (in C++!) Algebraic Data Types (in C++!) Algebraic Data Types (in C++!)
Easy ones Product Types Sum Types
- Can use enum when underlying types
- Unit (): use boost::mpl: void_ - z := a ⊗ ⊗ b c. struct. Named - are units, and
accessors - aren't used elsewhere.
- New unit types: T : = ()
struct T {}; -a ⊗ b. boost.fusion.vector. Access by - Can use a product type with an index.
index - common and error prone
- “is the same as”: a := b - Can use polymorphic base class.
typedef b a; - boost.fusion.map. Both accessor methods. - not really nice syntax/error prone
16 17 18
4. Algebraic Data Types (in C++!) Algebraic Data Types (in C++!) Algebraic Data Types (in C++!)
“is implemented with , : =, wrap it in a struct
”
Type Functions (:= style)
Use “type function trait” from boost.mpl.
Sum Types R01 : = double
- boost.variant (best option!) struct R01
- arbitrary underlying types { explicit R01( const double impl_ ) none : = (), Op a := none⊕ a
- small syntax overhead : impl( impl_ ) {} struct none{};
- access by index or type double impl; template< typename a >
}; struct Op {
- accessor functions (invariant typedef boost::variant<none,a>
a b c
⊕ ⊕ guaranteed)
boost::variant<a,b,c> - internal impl access function (invariant type;
19 requirement) 20
}; 21
Algebraic Data Types (in C++!) Algebraic Data Types (in C++!) What the heck is a recursive
Type Functions (::= style) product type?
Use a wrapper template struct Recursive Types
S a := a ⊗ (S a)
none : = (), Op a : = none
⊕ a - sum types: use make_recursive_variant
struct none{}; - Seems like nonsense!?
template< typename a > - product types: use
struct Op { make_recursive_variant (see
explicit Op( boost::variant<none,a>); paper for details)
//...
boost::variant<none,a> impl;
}; 22 23 24
5. What the heck is a recursive Laziness (in C++!) Laziness (in C++!)
product type?
How can we represent a computation of a How can we represent a computation of a
S a := a ⊗ (S a) value in C++? value in C++?
- Seems like nonsense!? - A 0 argument function.
- Nope
- Think of the recursion as being a
computation of type (S a)
- ...
25 26 27
Laziness (in C++!) What the heck is a recursive Functions
product type?
How can we represent a computation of a f:A → B
value in C++? S a := a ⊗ (S a)
- A 0 argument function. A set S of pairs (a,b) where a A b B. For
∈ ∈
- Streams of type a. See paper for a
template< typename a> direct implementation. every a A, there exists exactly one
∈
struct lazy
{ typedef boost::function< a () > corresponding pair in S.
type;
};
28 29 30
6. What is a C++ function? What is a C++ function? What is a C++ function?
bool f(int); bool f(int); => int bool
→ bool f(int); => int bool
→
What about multiple arguments?
31 32 33
What is a C++ function?
Lets try another case.
bool f2(int, int);
34
7. What is a C++ function? What is a C++ function? Currying
bool f3(int, int); (int int World)
⊗ ⊗ → Translation a⊗b→c
{ ++someglobalvar; (World bool)
⊗ to
a → (b → c)
R f(A1, A2,...,An);
return true; } ^^^
(A1
⊗ A2...An World) (World R)
⊗ → ⊗ - function returns a function (convenient)
- (int int) bool doesn't work!
→ ⊗ - → is right associative
- Consider the corresponding set. - Works with any function where
- Introduce new parameter the domain is a product.
and return value, World... 37 38 39
What is a C++ function?
Translation
R f(A1, A2,...,An);
(A1⊗A2...An⊗World)→(World⊗R)
^^^
A1→A2...An→World→(World⊗R)
^^^
40
8. Functions (in C++)
gfp library (netsuperbrain.com/gfp)
- gfp::ciof (curried io function)
- Converts a c++ function pointer into a
function as we formulated.
- gfp::cfunc (curried function)
- cfunc<a,b,c>::type =>
function<function<c (b)> a>
43
Generic Programming
Formulation:
- Emptiable, a type class
- A typeclass is a set of pairs (a,p)
- a is a : = type or type function
- p is a profile that fits certain
patterns and laws
- Our restrictions
- At most one pair per type
- Profile is a simple value
46
9. Generic Programming (in C++!)
Polymorphic Values:
- Same type inference trick doesn't work
for values.
- Introduce resolve:
resolve<std::vector<int>>( emptyThing );
- Polymorphic values must follow a
Certain trait . . .
51
Generic Programming (in C++!) Generic Programming (in C++!) Generic Programming (in C++!)
Polymorphic Values: Polymorphic Values & Functions: Polymorphic Classes:
struct EmptyThing - Covers all generics we care about - Extendable collections of polymorphic
{ template<typename T> - Cannot be extended to support new values and functions.
struct result; types without modification of underlying - Use partial template instantiation to
//... code. select supported type.
result<this_type(vector<int>*)>::type - No relation between related - The polymorphic entities select
operator()( vector<int>* dummy ); polymorphic values and functions. appropriate instantiation when
//... used.
} emptyThing;
52 53 54
10. Category Theory Category Theory Category Theory (Monoids)
- deals abstractly with mathematical Monoids There are lots of monoids!
structures and relations between them. A
0∈A
- int, +, 0 : sum monoid
+ :A → A → A
- bool, &&, true: all monoid
- Gives some guidance as to what to do - string, concat, “”: string monoid
with generics. - a → m: function monoid
A, 0, and + form a monoid when + is - m monoid
- Very powerful and expressive. associative and 0 is an identity for - forwards monoid operations to results.
+. - io m: io monoid. Similar to function monoid.
55 56 57
Category Theory (Monoids) Category Theory Functional Programming (in C++!)
Quick example: Much much more: FP Benefits:
- header : Message → string - Cleaner design → Cleaner code
- contents : Message → string - functor/pointed: functions, containers... - less code/static types → Less bugs
- Powerful tools
gfp::cfunc<Message,string> - idiom (applicative functors): FRP, streams FP (in C++) Benefits:
payload = gfp::mplus( header )( contents ); - No need to switch languages
- monad: arbitrary computations - Integrates well
- called point free (pointless) programming!. - Easy to use (no special syntax)
- foldable: compress collections - Highly Capable
58 59 60