How to define non-empty set in Coq? - math

Trying to create my first Coq definitions after doing many tutorials. Wondering how to define something simple like an alphabet, if the definition is:
Σ is an alphabet iff it's a finite nonempty set of symbols.
Got this much:
Require Import Coq.Lists.ListSet.
Definition alphabet := set.
But how do you specify the "must be a finite, non-empty set" part?

Since you choose your alphabet to be set, it is by definition finite, since set is defined as an instance of list, and inductive types are always finite.
The ListSet library you are using defines emptyset so your first option would be to state that
Definition not_empty (a: alphabet) : Prop := a <> empty_set.
Or you could rely on the fact that your set is list and pattern match on the expression:
Definition not_empty (a: alphabet) : bool := match a with
| nil => false
| _ => true
end.
(You can also define the latter in Prop instead of bool by using False and True.)
EDIT: Some clarification asked by Arthur (Simplification here, grab a real text-book about inductive types if you want a more precise explanation):
An inductive type can be inhabited by:
a finite number of elements (for example, bool),
an infinite number of elements (for example, nat)
no element at all (for example False).
However, any element of an inductive type is by construction finite. For example you can write any natural number by composing a finite number of time the constructor S but you have to use O at some point and ''stop'' the construction of your term. Same goes for lists: you can build an arbitrary long list, but its length will always be finite.

Related

Use a recursive dop in APL

In the tryapl.org Primer when you select the Del glyph (∇) it shows an example of a Double-Del (∇∇) where a dop (as I understand it, a user defined operator) can reference itself in a recursive fashion:
Double-Del Syntax: dop self-reference
pow←{ ⍝ power operator: apply ⍵⍵ times
⍵⍵=0:⍵ ⍝ ⍵⍵ is 0: finished
⍺⍺ ∇∇(⍵⍵-1)⍺⍺ ⍵ ⍝ otherwise: recurse
}
Can someone provide me with some examples of this particular dop in use so I can see how to utilize it? I see that a single ⍺ is not used in the body of this dop, only ⍺⍺; does that make this a monadic dop?
I have tried a number of different ways to use this operator in an expression after it's defined and can't seem to get anything but errors or instances where it appears the body/text of the dop is in an array as text, alongside what I was trying to pass to it.
Example usage
incr←{1+⍵} ⍝ define an increment function
(incr pow 3) 5 ⍝ apply it 3 times to 5
8
Lack of single ⍺
The operator has ⍵⍵ which alone makes it a dyadic operator. The lack of a single ⍺ means that, when given the two required operands, it derives a monadic function.
Troubleshooting
When an operator takes an array (as opposed to a function) operand adjacent to an argument, it is crucial to separate the operand from the argument. This can be done in any of three ways:
Name the derived function and then apply it:add3←incr pow 3
add3 5
Parenthesise the derived function:(incr pow 3) 5
Separate the operand from the argument using a function (often, the identity function ⊢ is used): incr pow 3 ⊢ 5
Failing this, the intended operand and argument will strand to a single array, which then becomes the operand, leaving the derived function with no argument that it can apply to:
incr pow (3 5)
The result is therefore the derived function; the text source you see reported.

Proving mutual recursion is well-founded in Lean

I am trying to define the semantics of a programming language in Lean. To do so, I have a bunch of mutually inductive types defining the different term types of the language:
mutual inductive CBlockList, Block, SwitchBody, CExpr, CStatement
with CBlockList : FTContext → set Identifier -> set Identifier -> Type
....
with Block : FTContext → set Identifier → Type
...
with SwitchBody : FTContext → set Identifier → Type
...
with CExpr : FTContext → set Identifier → ℕ → Type
...
with CStatement : FTContext → set Identifier → set Identifier → Type
...
Note that in particular, the different term types take a function typing context and a set of identifier in scope as arguments. Terms that can introduce new variables into scope have a second such argument, defining the set of arguments after the term is evaluated.
However, when defining mutually recursive functions over this mutually recursive data type, lean complains that for some of the recursive calls, it is unable to infer well-foundedness. This occurs in particular when there are calls between functions with different numbers of arguments (because of the different number of arguments of the associated types). Lean seems to try to define the well-founded order over the sum of the dependent product of each function's arguments, but when they have different number of arguments, it, I assume, does not give any order to these elements of the set, hence the problem I have encountered.
I have tried to define a mutually recursive depth function that traverse the mutually inductive data types and returns a limit to the possible depth of recursion to be able to prove well-foundedness myself, however, this function definition runs into the same problem. It seems I'm stuck in a catch-22.
How would I go about solving such a problem?

How to pass assumptions to interpretation of locale

I would like to use some properties of my structure in the proof required by a locale interpretation
As an example, suppose I defined the predicate P and proved some lemmas (add is a closed binary operation, add is associative and there exists zero the neutral element) about the add operation on elements that satisfy the predicate P
I would like to interpret then the set of my elements as a structure that
satisfy some locale, e.g. monoid
interpretation "{s . P s}" :: monoid "(add)" "(zero)"
unfolding
monoid_def
using
add_is_associative
zero_is_neutral
but then in the goal of my proof I am not able to get that all the elements
are actually satisfying the predicate P and I am left with a generic goal
such as add zero a = a which I already proved for elements in my set.
How to enforce in my goal that all the elements satisfy the predicate P?
I will make an attempt to provide comments on your question. Please feel free to ask further questions in the comments if you will find that my comments are not sufficient to answer your question.
Firstly, I would like to mention that there exists a good tutorial on locales and locale interpretation in the standard documentation of Isabelle. The name of the document is "Tutorial to Locales and Locale Interpretation" (by Clemens Ballarin). The document also contains several useful references.
After studying the tutorial and the references, it may also be useful to look at section 5.7 in the document "The Isabelle/Isar Reference Manual".
I would like to use some properties of my structure in the proof
required by a locale interpretation
The description of the locale interpretation in the reference manual states that
Locales may be instantiated, and the resulting instantiated
declarations added to the current context. This requires proof (of the
instantiated specification) and is called locale interpretation.
When you invoke the command interpretation with a set of appropriately stated arguments, the goals that are discharged by the command depend solely on the arguments. The proof that you provide to prove the discharged goals will have no impact on the 'resulting instantiated declarations'. Thus, technically, it does not matter whether or not you use the properties of your functions that you mentioned explicitly to prove the interpretation.
I would like to interpret then the set of my elements as a structure
that satisfy some locale, e.g. monoid:
interpretation "{s . P s}" :: monoid "(add)" "(zero)"
If you look at the specification of the command interpretation in the reference manual (section 5.7.3), you will realise that as its input argument the command takes a 'locale expression'. The 'locale expression' is described in section 5.7.1 in the reference manual. Here, I present a significantly simplified (incomplete) description of the locale expression:
qualifier : name pos_insts
The field 'qualifier' is optional and the field 'name' is reserved for the name of the locale that you are trying to interpret. Therefore, the expression "{s . P s}" :: monoid "(add)" "(zero)" that you provided in your question is not a valid locale expression. I can only guess that you meant to use a single colon instead of the double colon ::, i.e. "{s . P s}" : monoid "(add)" "(zero)" and I will proceed with the answer based on this assumption.
In the example that you provided, the 'qualifier' is "{s . P s}", the 'name' is monoid and the 'pos_insts' are, effectively, the terms specified after the name.
Returning to the documentation you will also find the description of the field 'qualifier':
Instances have an optional qualifier which applies to names in
declarations
...
Qualifiers only affect name spaces; they play no role in
determining whether one locale instance subsumes another.
Thus, the qualifier "{s . P s}" that you specified can only have an effect on the names of the declarations. It will have no effect on the goals discharged by the command and its output.
interpretation "{s . P s}" : monoid "(add)" "(zero)"
Returning to your example, if you are referring to the locale monoid from the theory HOL-Groups, then, if you study its specification and also the specification of the locale semigroup, you will be able to infer that the locale monoid has two parameters that are associated with it: f and z. There are no other parameters and the 'carrier set' of the monoid associated with the locale consists of all terms of a given type.
locale monoid = semigroup +
fixes z :: 'a ("❙1")
assumes left_neutral [simp]: "❙1 ❙* a = a"
assumes right_neutral [simp]: "a ❙* ❙1 = a"
In conclusion, the locale monoid from the theory HOL-Groups is not suitable for representation of a monoid on an explicit carrier set that is a proper subset of the terms of a given type.
For your application, you will need to use a locale that represents a monoid on an explicit carrier set, for example, the locale monoid from the theory HOL-Algebra.Group. You can see examples of its interpretation in the theory HOL-Algebra.IntRing.
UPDATE
Following the request of the author of the question given in the comments, I provide an example of an interpretation of the locale monoid from the theory HOL-Algebra.Group:
theory SO_Question
imports "HOL-Algebra.Group"
begin
abbreviation even_monoid :: "int monoid" ("𝒵⇩2") where
"even_monoid ≡ ⦇carrier = {x. x mod 2 = 0}, mult = (+), one = 0::int⦈"
interpretation even_monoid: monoid 𝒵⇩2
by unfold_locales auto+
end

Using "find_theorems" in Isabelle

I want to find theorems. I have read the section on find_theorems in the Isabelle/Isar reference manual:
find_theorems criteria
Retrieves facts from the theory or proof context matching all of given search
criteria. The criterion name: p selects all theorems whose fully qualified
name matches pattern p, which may contain "*" wildcards. The criteria intro,
elim, and dest select theorems that match the current goal as introduction,
elimination or destruction rules, respectively. The criterion solves returns
all rules that would directly solve the current goal. The criterion simp: t
selects all rewrite rules whose left-hand side matches the given term. The
criterion term t selects all theorems that contain the pattern t -- as usual,
patterns may contain occurrences of the dummy "_" , schematic variables, and
type constraints.
Criteria can be preceded by "-" to select theorems that do not match. Note
that giving the empty list of criteria yields all currently known facts. An
optional limit for the number of printed facts may be given; the default is 40.
By default, duplicates are removed from the search result. Use with_dups to
display duplicates.
As far as I understand, find_theorems is used in the find window of Isabelle/jEdit. The above does not help me finding relevant theorems for the following situation (Lambda is a theory of the Nominal Isabelle extension. The tarball is here):
theory First
imports Lambda
begin
theorem "Lam [x].(Lam [y].(App (Var x)(Var y))) = Lam [y].(Lam [x].(App (Var y)(Var x)))"
When I try the search expression Lam Isabelle/jedit says
Inner syntax error: unexpected end of input
Failed to parse term
How can I make it look for all the theorems that contain the constant Lam?
Since Lam like the ordinary lambda (%) is not a term on its own, you should add the remaining parts to get a proper term, which may contain wildcards. In your example, I would perform
find_theorems "Lam [_]. _"
which gives lots of answers.
Typically this happens whenever special syntax was defined for some constant. But there is (almost) always an underlying ("raw") constant. To find out which constant provides the Lam [_]. _ syntax. You can Ctrl-click Lam (inside a proper term) within Isabelle/jEdit. This will jump to the definition of the underlying constant.
For Lam there is the additional complication that the binder syntax uses exactly the same string as the underlying constant, namely Lam, as can be seen at the place of definition:
nominal_datatype lam =
Var "name"
| App "lam" "lam"
| Lam x::"name" l::"lam" binds x in l ("Lam [_]. _" [100, 100] 100)
In such cases you can use the long name of the constant by prefixing it with the theory name, i.e., Lambda.Lam.
Note: The same works for binders like ALL x. P x (with underlying constant All), but not for the built-in %x. x.

In Functional Programming, what is a functor?

I've come across the term 'Functor' a few times while reading various articles on functional programming, but the authors typically assume the reader already understands the term. Looking around on the web has provided either excessively technical descriptions (see the Wikipedia article) or incredibly vague descriptions (see the section on Functors at this ocaml-tutorial website).
Can someone kindly define the term, explain its use, and perhaps provide an example of how Functors are created and used?
Edit: While I am interested in the theory behind the term, I am less interested in the theory than I am in the implementation and practical use of the concept.
Edit 2: Looks like there is some cross-terminoligy going on: I'm specifically referring to the Functors of functional programming, not the function objects of C++.
The word "functor" comes from category theory, which is a very general, very abstract branch of mathematics. It has been borrowed by designers of functional languages in at least two different ways.
In the ML family of languages, a functor is a module that takes one or more other modules as a parameter. It's considered an advanced feature, and most beginning programmers have difficulty with it.
As an example of implementation and practical use, you could define your favorite form of balanced binary search tree once and for all as a functor, and it would take as a parameter a module that provides:
The type of key to be used in the binary tree
A total-ordering function on keys
Once you've done this, you can use the same balanced binary tree implementation forever. (The type of value stored in the tree is usually left polymorphic—the tree doesn't need to look at values other than to copy them around, whereas the tree definitely needs to be able to compare keys, and it gets the comparison function from the functor's parameter.)
Another application of ML functors is layered network protocols. The link is to a really terrific paper by the CMU Fox group; it shows how to use functors to build more complex protocol layers (like TCP) on type of simpler layers (like IP or even directly over Ethernet). Each layer is implemented as a functor that takes as a parameter the layer below it. The structure of the software actually reflects the way people think about the problem, as opposed to the layers existing only in the mind of the programmer. In 1994 when this work was published, it was a big deal.
For a wild example of ML functors in action, you could see the paper ML Module Mania, which contains a publishable (i.e., scary) example of functors at work. For a brilliant, clear, pellucid explanation of the ML modules system (with comparisons to other kinds of modules), read the first few pages of Xavier Leroy's brilliant 1994 POPL paper Manifest Types, Modules, and Separate Compilation.
In Haskell, and in some related pure functional language, Functor is a type class. A type belongs to a type class (or more technically, the type "is an instance of" the type class) when the type provides certain operations with certain expected behavior. A type T can belong to class Functor if it has certain collection-like behavior:
The type T is parameterized over another type, which you should think of as the element type of the collection. The type of the full collection is then something like T Int, T String, T Bool, if you are containing integers, strings, or Booleans respectively. If the element type is unknown, it is written as a type parameter a, as in T a.
Examples include lists (zero or more elements of type a), the Maybe type (zero or one elements of type a), sets of elements of type a, arrays of elements of type a, all kinds of search trees containing values of type a, and lots of others you can think of.
The other property that T has to satisfy is that if you have a function of type a -> b (a function on elements), then you have to be able to take that function and product a related function on collections. You do this with the operator fmap, which is shared by every type in the Functor type class. The operator is actually overloaded, so if you have a function even with type Int -> Bool, then
fmap even
is an overloaded function that can do many wonderful things:
Convert a list of integers to a list of Booleans
Convert a tree of integers to a tree of Booleans
Convert Nothing to Nothing and Just 7 to Just False
In Haskell, this property is expressed by giving the type of fmap:
fmap :: (Functor t) => (a -> b) -> t a -> t b
where we now have a small t, which means "any type in the Functor class."
To make a long story short, in Haskell a functor is a kind of collection for which if you are given a function on elements, fmap will give you back a function on collections. As you can imagine, this is an idea that can be widely reused, which is why it is blessed as part of Haskell's standard library.
As usual, people continue to invent new, useful abstractions, and you may want to look into applicative functors, for which the best reference may be a paper called Applicative Programming with Effects by Conor McBride and Ross Paterson.
Other answers here are complete, but I'll try another explanation of the FP use of functor. Take this as analogy:
A functor is a container of type a that, when subjected to a function that maps from a→b, yields a container of type b.
Unlike the abstracted-function-pointer use in C++, here the functor is not the function; rather, it's something that behaves consistently when subjected to a function.
There are three different meanings, not much related!
In Ocaml it is a parametrized module. See manual. I think the best way to grok them is by example: (written quickly, might be buggy)
module type Order = sig
type t
val compare: t -> t -> bool
end;;
module Integers = struct
type t = int
let compare x y = x > y
end;;
module ReverseOrder = functor (X: Order) -> struct
type t = X.t
let compare x y = X.compare y x
end;;
(* We can order reversely *)
module K = ReverseOrder (Integers);;
Integers.compare 3 4;; (* this is false *)
K.compare 3 4;; (* this is true *)
module LexicographicOrder = functor (X: Order) ->
functor (Y: Order) -> struct
type t = X.t * Y.t
let compare (a,b) (c,d) = if X.compare a c then true
else if X.compare c a then false
else Y.compare b d
end;;
(* compare lexicographically *)
module X = LexicographicOrder (Integers) (Integers);;
X.compare (2,3) (4,5);;
module LinearSearch = functor (X: Order) -> struct
type t = X.t array
let find x k = 0 (* some boring code *)
end;;
module BinarySearch = functor (X: Order) -> struct
type t = X.t array
let find x k = 0 (* some boring code *)
end;;
(* linear search over arrays of integers *)
module LS = LinearSearch (Integers);;
LS.find [|1;2;3] 2;;
(* binary search over arrays of pairs of integers,
sorted lexicographically *)
module BS = BinarySearch (LexicographicOrder (Integers) (Integers));;
BS.find [|(2,3);(4,5)|] (2,3);;
You can now add quickly many possible orders, ways to form new orders, do a binary or linear search easily over them. Generic programming FTW.
In functional programming languages like Haskell, it means some type constructors (parametrized types like lists, sets) that can be "mapped". To be precise, a functor f is equipped with (a -> b) -> (f a -> f b). This has origins in category theory. The Wikipedia article you linked to is this usage.
class Functor f where
fmap :: (a -> b) -> (f a -> f b)
instance Functor [] where -- lists are a functor
fmap = map
instance Functor Maybe where -- Maybe is option in Haskell
fmap f (Just x) = Just (f x)
fmap f Nothing = Nothing
fmap (+1) [2,3,4] -- this is [3,4,5]
fmap (+1) (Just 5) -- this is Just 6
fmap (+1) Nothing -- this is Nothing
So, this is a special kind of a type constructors, and has little to do with functors in Ocaml!
In imperative languages, it is a pointer to function.
In OCaml, it's a parameterised module.
If you know C++, think of an OCaml functor as a template. C++ only has class templates, and functors work at the module scale.
An example of functor is Map.Make; module StringMap = Map.Make (String);; builds a map module that works with String-keyed maps.
You couldn't achieve something like StringMap with just polymorphism; you need to make some assumptions on the keys. The String module contains the operations (comparison, etc) on a totally ordered string type, and the functor will link against the operations the String module contains. You could do something similar with object-oriented programming, but you'd have method indirection overhead.
You got quite a few good answers. I'll pitch in:
A functor, in the mathematical sense, is a special kind of function on an algebra. It is a minimal function which maps an algebra to another algebra. "Minimality" is expressed by the functor laws.
There are two ways to look at this. For example, lists are functors over some type. That is, given an algebra over a type 'a', you can generate a compatible algebra of lists containing things of type 'a'. (For example: the map that takes an element to a singleton list containing it: f(a) = [a]) Again, the notion of compatibility is expressed by the functor laws.
On the other hand, given a functor f "over" a type a, (that is, f a is the result of applying the functor f to the algebra of type a), and function from g: a -> b, we can compute a new functor F = (fmap g) which maps f a to f b. In short, fmap is the part of F that maps "functor parts" to "functor parts", and g is the part of the function that maps "algebra parts" to "algebra parts". It takes a function, a functor, and once complete, it IS a functor too.
It might seem that different languages are using different notions of functors, but they're not. They're merely using functors over different algebras. OCamls has an algebra of modules, and functors over that algebra let you attach new declarations to a module in a "compatible" way.
A Haskell functor is NOT a type class. It is a data type with a free variable which satisfies the type class. If you're willing to dig into the guts of a datatype (with no free variables), you can reinterpret a data type as a functor over an underlying algebra. For example:
data F = F Int
is isomorphic to the class of Ints. So F, as a value constructor, is a function that maps Int to F Int, an equivalent algebra. It is a functor. On the other hand, you don't get fmap for free here. That's what pattern matching is for.
Functors are good for "attaching" things to elements of algebras, in an algebraically compatible way.
The best answer to that question is found in "Typeclassopedia" by Brent Yorgey.
This issue of Monad Reader contain a precise definition of what a functor is as well as many definition of other concepts as well as a diagram. (Monoid, Applicative, Monad and other concept are explained and seen in relation to a functor).
http://haskell.org/sitewiki/images/8/85/TMR-Issue13.pdf
excerpt from Typeclassopedia for Functor:
"A simple intuition is that a Functor represents a “container” of some
sort, along with the ability to apply a function uniformly to every element in the
container"
But really the whole typeclassopedia is a highly recommended reading that is surprisingly easy. In a way you can see the typeclass presented there as a parallel to design pattern in object in the sense that they give you a vocabulary for given behavior or capability.
Cheers
There is a pretty good example in the O'Reilly OCaml book that's on Inria's website (which as of writing this is unfortunately down). I found a very similar example in this book used by caltech: Introduction to OCaml (pdf link). The relevant section is the chapter on functors (Page 139 in the book, page 149 in the PDF).
In the book they have a functor called MakeSet which creates a data structure that consists of a list, and functions to add an element, determine if an element is in the list, and to find the element. The comparison function that is used to determine if it's in/not in the set has been parametrized (which is what makes MakeSet a functor instead of a module).
They also have a module that implements the comparison function so that it does a case insensitive string compare.
Using the functor and the module that implements the comparison they can create a new module in one line:
module SSet = MakeSet(StringCaseEqual);;
that creates a module for a set data structure that uses case insensitive comparisons. If you wanted to create a set that used case sensitive comparisons then you would just need to implement a new comparison module instead of a new data structure module.
Tobu compared functors to templates in C++ which I think is quite apt.
Given the other answers and what I'm going to post now, I'd say that it's a rather heavily overloaded word, but anyway...
For a hint regarding the meaning of the word 'functor' in Haskell, ask GHCi:
Prelude> :info Functor
class Functor f where
fmap :: forall a b. (a -> b) -> f a -> f b
(GHC.Base.<$) :: forall a b. a -> f b -> f a
-- Defined in GHC.Base
instance Functor Maybe -- Defined in Data.Maybe
instance Functor [] -- Defined in GHC.Base
instance Functor IO -- Defined in GHC.Base
So, basically, a functor in Haskell is something that can be mapped over. Another way to say it is that a functor is something which can be regarded as a container which can be asked to use a given function to transform the value it contains; thus, for lists, fmap coincides with map, for Maybe, fmap f (Just x) = Just (f x), fmap f Nothing = Nothing etc.
The Functor typeclass subsection and the section on Functors, Applicative Functors and Monoids of Learn You a Haskell for Great Good give some examples of where this particular concept is useful. (A summary: lots of places! :-))
Note that any monad can be treated as a functor, and in fact, as Craig Stuntz points out, the most often used functors tend to be monads... OTOH, it is convenient at times to make a type an instance of the Functor typeclass without going to the trouble of making it a Monad. (E.g. in the case of ZipList from Control.Applicative, mentioned on one of the aforementioned pages.)
"Functor is mapping of objects and morphisms that preserves composition and identity of a category."
Lets define what is a category ?
It's a bunch of objects!
Draw a few dots (for now 2 dots, one is 'a' another is 'b') inside a
circle and name that circle A(Category) for now.
What does the category holds ?
Composition between objects and Identity function for every object.
So, we have to map the objects and preserve the composition after applying our Functor.
Lets imagine 'A' is our category which has objects ['a', 'b'] and there exists a morphism a -> b
Now, we have to define a functor which can map these objects and morphisms into another category 'B'.
Lets say the functor is called 'Maybe'
data Maybe a = Nothing | Just a
So, The category 'B' looks like this.
Please draw another circle but this time with 'Maybe a' and 'Maybe b' instead of 'a' and 'b'.
Everything seems good and all the objects are mapped
'a' became 'Maybe a' and 'b' became 'Maybe b'.
But the problem is we have to map the morphism from 'a' to 'b' as well.
That means morphism a -> b in 'A' should map to morphism 'Maybe a' -> 'Maybe b'
morphism from a -> b is called f, then morphism from 'Maybe a' -> 'Maybe b' is called 'fmap f'
Now lets see what function 'f' was doing in 'A' and see if we can replicate it in 'B'
function definition of 'f' in 'A':
f :: a -> b
f takes a and returns b
function definition of 'f' in 'B' :
f :: Maybe a -> Maybe b
f takes Maybe a and return Maybe b
lets see how to use fmap to map the function 'f' from 'A' to function 'fmap f' in 'B'
definition of fmap
fmap :: (a -> b) -> (Maybe a -> Maybe b)
fmap f Nothing = Nothing
fmap f (Just x) = Just(f x)
So, what are we doing here ?
We are applying the function 'f' to 'x' which is of type 'a'. Special pattern matching of 'Nothing' comes from the definition of Functor Maybe.
So, we mapped our objects [a, b] and morphisms [ f ] from category 'A' to category 'B'.
Thats Functor!
Here's an article on functors from a programming POV, followed up by more specifically how they surface in programming languages.
The practical use of a functor is in a monad, and you can find many tutorials on monads if you look for that.
In a comment to the top-voted answer, user Wei Hu asks:
I understand both ML-functors and Haskell-functors, but lack the
insight to relate them together. What's the relationship between these
two, in a category-theoretical sense?
Note: I don't know ML, so please forgive and correct any related mistakes.
Let's initially assume that we are all familiar with the definitions of 'category' and 'functor'.
A compact answer would be that "Haskell-functors" are (endo-)functors F : Hask -> Hask while "ML-functors" are functors G : ML -> ML'.
Here, Hask is the category formed by Haskell types and functions between them, and similarly ML and ML' are categories defined by ML structures.
Note: There are some technical issues with making Hask a category, but there are ways around them.
From a category theoretic perspective, this means that a Hask-functor is a map F of Haskell types:
data F a = ...
along with a map fmap of Haskell functions:
instance Functor F where
fmap f = ...
ML is pretty much the same, though there is no canonical fmap abstraction I am aware of, so let's define one:
signature FUNCTOR = sig
type 'a f
val fmap: 'a -> 'b -> 'a f -> 'b f
end
That is f maps ML-types and fmap maps ML-functions, so
functor StructB (StructA : SigA) :> FUNCTOR =
struct
fmap g = ...
...
end
is a functor F: StructA -> StructB.
Rough Overview
In functional programming, a functor is essentially a construction of lifting ordinary unary functions (i.e. those with one argument) to functions between variables of new types. It is much easier to write and maintain simple functions between plain objects and use functors to lift them, then to manually write functions between complicated container objects. Further advantage is to write plain functions only once and then re-use them via different functors.
Examples of functors include arrays, "maybe" and "either" functors, futures (see e.g. https://github.com/Avaq/Fluture), and many others.
Illustration
Consider the function constructing the full person's name from the first and last names. We could define it like fullName(firstName, lastName) as function of two arguments, which however would not be suitable for functors that only deal with functions of one arguments. To remedy, we collect all the arguments in a single object name, which now becomes the function's single argument:
// In JavaScript notation
fullName = name => name.firstName + ' ' + name.lastName
Now what if we have many people in an array? Instead of manually go over the list, we can simply re-use our function fullName via the map method provided for arrays with short single line of code:
fullNameList = nameList => nameList.map(fullName)
and use it like
nameList = [
{firstName: 'Steve', lastName: 'Jobs'},
{firstName: 'Bill', lastName: 'Gates'}
]
fullNames = fullNameList(nameList)
// => ['Steve Jobs', 'Bill Gates']
That will work, whenever every entry in our nameList is an object providing both firstName and lastName properties. But what if some objects don't (or even aren't objects at all)? To avoid the errors and make the code safer, we can wrap our objects into the Maybe type (se e.g. https://sanctuary.js.org/#maybe-type):
// function to test name for validity
isValidName = name =>
(typeof name === 'object')
&& (typeof name.firstName === 'string')
&& (typeof name.lastName === 'string')
// wrap into the Maybe type
maybeName = name =>
isValidName(name) ? Just(name) : Nothing()
where Just(name) is a container carrying only valid names and Nothing() is the special value used for everything else. Now instead of interrupting (or forgetting) to check the validity of our arguments, we can simply reuse (lift) our original fullName function with another single line of code, based again on the map method, this time provided for the Maybe type:
// Maybe Object -> Maybe String
maybeFullName = maybeName => maybeName.map(fullName)
and use it like
justSteve = maybeName(
{firstName: 'Steve', lastName: 'Jobs'}
) // => Just({firstName: 'Steve', lastName: 'Jobs'})
notSteve = maybeName(
{lastName: 'SomeJobs'}
) // => Nothing()
steveFN = maybeFullName(justSteve)
// => Just('Steve Jobs')
notSteveFN = maybeFullName(notSteve)
// => Nothing()
Category Theory
A Functor in Category Theory is a map between two categories respecting composition of their morphisms. In a Computer Language, the main Category of interest is the one whose objects are types (certain sets of values), and whose morphisms are functions f:a->b from one type a to another type b.
For example, take a to be the String type, b the Number type, and f is the function mapping a string into its length:
// f :: String -> Number
f = str => str.length
Here a = String represents the set of all strings and b = Number the set of all numbers. In that sense, both a and b represent objects in the Set Category (which is closely related to the category of types, with the difference being inessential here). In the Set Category, morphisms between two sets are precisely all functions from the first set into the second. So our length function f here is a morphism from the set of strings into the set of numbers.
As we only consider the set category, the relevant Functors from it into itself are maps sending objects to objects and morphisms to morphisms, that satisfy certain algebraic laws.
Example: Array
Array can mean many things, but only one thing is a Functor -- the type construct, mapping a type a into the type [a] of all arrays of type a. For instance, the Array functor maps the type String into the type [String] (the set of all arrays of strings of arbitrary length), and set type Number into the corresponding type [Number] (the set of all arrays of numbers).
It is important not to confuse the Functor map
Array :: a => [a]
with a morphism a -> [a]. The functor simply maps (associates) the type a into the type [a] as one thing to another. That each type is actually a set of elements, is of no relevance here. In contrast, a morphism is an actual function between those sets. For instance, there is a natural morphism (function)
pure :: a -> [a]
pure = x => [x]
which sends a value into the 1-element array with that value as single entry. That function is not a part of the Array Functor! From the point of view of this functor, pure is just a function like any other, nothing special.
On the other hand, the Array Functor has its second part -- the morphism part. Which maps a morphism f :: a -> b into a morphism [f] :: [a] -> [b]:
// a -> [a]
Array.map(f) = arr => arr.map(f)
Here arr is any array of arbitrary length with values of type a, and arr.map(f) is the array of the same length with values of type b, whose entries are results of applying f to the entries of arr. To make it a functor, the mathematical laws of mapping identity to identity and compositions to compositions must hold, which are easy to check in this Array example.
Not to contradict the previous theoretical or mathematical answers, but a Functor is also an Object (in an Object-Oriented programming language) that has only one method and is effectively used as a function.
An example is the Runnable interface in Java, which has only one method: run.
Consider this example, first in Javascript, which has first-class functions:
[1, 2, 5, 10].map(function(x) { return x*x; });
Output:
[1, 4, 25, 100]
The map method takes a function and returns a new array with each element being the result of the application of that function to the value at the same position in the original array.
To do the same thing is Java, using a Functor, you would first need to define an interface, say:
public interface IntMapFunction {
public int f(int x);
}
Then, if you add a collection class which had a map function, you could do:
myCollection.map(new IntMapFunction() { public int f(int x) { return x * x; } });
This uses an in-line subclass of IntMapFunction to create a Functor, which is the OO equivalent of the function from the earlier JavaScript example.
Using Functors let you apply functional techniques in an OO language. Of course, some OO languages also have support for functions directly, so this isn't required.
Reference: http://en.wikipedia.org/wiki/Function_object
KISS: A functor is an object that has a map method.
Arrays in JavaScript implement map and are therefore functors. Promises, Streams and Trees often implement map in functional languages, and when they do, they are considered functors. The map method of the functor takes it’s own contents and transforms each of them using the transformation callback passed to map, and returns a new functor, which contains the structure as the first functor, but with the transformed values.
src: https://www.youtube.com/watch?v=DisD9ftUyCk&feature=youtu.be&t=76
In functional programming, error handling is different. Throwing and catching exceptions is imperative code. Instead of using try/catch block, a safety box is created around the code that might throw an error. this is a fundamental design pattern in functional programming. A wrapper object is used to encapsulate a potentially erroneous value. The wrapper's main purpose is to provide a 'different' way to use the wrapped object
const wrap = (val) => new Wrapper(val);
Wrapping guards direct access to the values so they can be manipulated
safely and immutably. Because we won’t have direct access to it, the only way to extract it is to use the identity function.
identity :: (a) -> a
This is another use case of identity function: Extracting data functionally from encapsulated types.
The Wrapper type uses the map to safely access and manipulate values. In this case, we are mapping the identity function over the container to extract the value from the container. With this approach, we can check for null before calling the function, or check for an empty string, a negative number, and so on.
fmap :: (A -> B) -> Wrapper[A] -> Wrapper[B]
fmap, first opens the container, then applies the given function to its value, and finally closes the value back into a new container of the same type. This type of function is called a functor.
fmap returns a new copy of the container at each invocation.
functors are side-effect-free
functors must be composable
In practice, functor means an object that implements the call operator in C++. In ocaml I think functor refers to something that takes a module as input and output another module.
Put simply, a functor, or function object, is a class object that can be called just like a function.
In C++:
This is how you write a function
void foo()
{
cout << "Hello, world! I'm a function!";
}
This is how you write a functor
class FunctorClass
{
public:
void operator ()
{
cout << "Hello, world! I'm a functor!";
}
};
Now you can do this:
foo(); //result: Hello, World! I'm a function!
FunctorClass bar;
bar(); //result: Hello, World! I'm a functor!
What makes these so great is that you can keep state in the class - imagine if you wanted to ask a function how many times it has been called. There's no way to do this in a neat, encapsulated way. With a function object, it's just like any other class: you'd have some instance variable that you increment in operator () and some method to inspect that variable, and everything's neat as you please.
Functor is not specifically related to functional programming. It's just a "pointer" to a function or some kind of object, that can be called as it would be a function.

Resources