Wolfgang JeltschMathematics, computer science, and computers2015-01-31T22:06:16Zhttp://jeltsch.wordpress.com/feed/atom/WordPress.comWolfgang Jeltschhttps://jeltsch.wordpress.com/http://jeltsch.wordpress.com/?p=6082014-10-31T10:52:17Z2014-10-31T10:52:17Z]]>Yesterday, I updated the Grapefruit FRP library once again, this time to make it compatible with GHC 7.8. The new version is 0.1.0.5. To install or update, you can use the following commands:

cabal update
cabal install grapefruit-ui-gtk grapefruit-examples

Many thanks to Samuel Gélineau for providing several patches. (By the way, Samuel maintains an interesting page that compares different FRP libraries, the FRP Zoo.)

Grapefruit 0.1 is actually a phase-out model, which I only update to work with newer GHC versions. However, I am working on a new Grapefruit. This will be based on my research about FRP semantics and will be quite different from the old one. I expect that the sound theoretical foundation will lead to a more powerful library with a more sensible interface. One particular new feature will be integration of side effects into FRP, in a purely functional style.

Tagged: FRP, Grapefruit, Haskell, Samuel Gélineau]]>0Wolfgang Jeltschhttps://jeltsch.wordpress.com/http://jeltsch.wordpress.com/?p=6062014-09-30T16:22:47Z2014-09-30T16:22:47Z]]>The list of publications and talks on my website has been pretty much out of date. Now it is updated, for you to enjoy. :-) Tagged: publication, talk]]>0Wolfgang Jeltschhttps://jeltsch.wordpress.com/http://jeltsch.wordpress.com/?p=6002014-02-25T22:24:00Z2014-02-25T22:23:02Z]]>On 13 February, I talked about hyperreal numbers in the Theory Lunch. I have not yet managed to write a blog article about this, but my notes on the whiteboard have already been featured on Estonian TV.

You can watch the video online. The relevant part, which is about e-government, is from 18:14 to 21:18. I enjoyed it very much hearing Ahto Kalja’s colleague Arvo Ott talking about electronic tax returns and seeing some formula about limits immediately afterwards. :-) At 20:38, there is also some Haskell-like pseudocode.

Like Haskell, Curry has support for literate programming. So I wrote this blog post as a literate Curry file, which is available for download. If you want to try out the code, you have to install the Curry system KiCS2. The code uses the functional patterns language extension, which is only supported by KiCS2, as far as I know.

Functional programming

The functional fragment of Curry is very similar to Haskell. The only fundamental difference is that Curry does not support type classes.

Let us do some functional programming in Curry. First, we define a type whose values denote me and some of my relatives.

Now we define a function that yields the father of a given person if this father is covered by the Person type.

father ::Person->Person
father Joachim=Paul
father Rita=Joachim
father Wolfgang=Joachim
father Veronika=Joachim
father Johanna=Wolfgang
father Jonathan=Wolfgang
father Jaromir=Wolfgang

Based on father, we define a function for computing grandfathers. To keep things simple, we only consider fathers of fathers to be grandfathers, not fathers of mothers.

grandfather ::Person->Person
grandfather = father . father

Combining functional and logic programming

Logic programming languages like Prolog are able to search for variable assignments that make a given proposition true. Curry, on the other hand, can search for variable assignments that make a certain expression defined.

For example, we can search for all persons that have a grandfather according to the above data. We just enter

grandfather person where person free

at the KiCS2 prompt. KiCS2 then outputs all assignments to the person variable for which grandfather person is defined. For each of these assignments, it additionally prints the result of the expression grandfather person.

Nondeterminism

Functions in Curry can actually be non-deterministic, that is, they can return multiple results. For example, we can define a function element that returns any element of a given list. To achieve this, we use overlapping patterns in our function definition. If several equations of a function definition match a particular function application, Curry takes all of them, not only the first one, as Haskell does.

Logic programming

We have already seen how to combine functional and logic programming with Curry. Now we want to do pure logic programming. This means that we only want to search for variable assignments, but are not interested in expression results. If you are not interested in results, you typically use a result type with only a single value. Curry provides the type Success with the single value success for doing logic programming.

Let us write some example code about routes between countries. We first introduce a type of some European and American countries.

Now we want to define a relation called borders that tells us which country borders which other country. We implement this relation as a function of type

Country -> Country -> Success

that has the trivial result success if the first country borders the second one, and has no result otherwise.

Note that this approach of implementing a relation is different from what we do in functional programming. In functional programming, we use Bool as the result type and signal falsity by the result False. In Curry, however, we signal falsity by the absence of a result.

Our borders relation only relates countries with those neighbouring countries whose names come later in alphabetical order. We will soon compute the symmetric closure of borders to also get the opposite relationships.

Now we want to define a relation isConnected that tells whether two countries can be reached from each other via a land route. Clearly, isConnected is the equivalence relation that is generated by borders. In Prolog, we would write clauses that directly express this relationship between borders and isConnected. In Curry, on the other hand, we can write a function that generates an equivalence relation from any given relation and therefore does not only work with borders.

We define the function for generating equivalence relations as a composition of the above closure operators. Note that it is crucial that the transitive closure operator is applied after the symmetric closure operator, since the symmetric closure of a transitive relation is not necessarily transitive.

Now we let KiCS2 compute which countries I can reach from Estonia without a ship or plane. We do so by entering

Estonia `isConnected` country where country free

at the prompt.

We can also implement a nondeterministic function that turns a country into the countries connected to it. For this, we use a guard that is of type Success. Such a guard succeeds if it has a result at all, which can only be success, of course.

Equational constraints

Curry has a predefined operator

=:= :: val -> val -> Success

that stands for equality.

We can use this operator, for example, to define a nondeterministic function that yields the grandchildren of a given person. Again, we keep things simple by only considering relationships that solely go via fathers.

With this operator, we could also implement grandchild as inverse grandfather.

Inverting functions can make our lives a lot easier. Consider the example of parsing. A parser takes a string and returns a syntax tree. Writing a parser directly is a non-trivial task. However, generating a string from a syntax tree is just a simple functional programming exercise. So we can implement a parser in a simple way by writing a converter from syntax trees to strings and inverting it.

We show this for the language of all arithmetic expressions that can be built from addition, multiplication, and integer constants. We first define types for representing abstract syntax trees. These types resemble a grammar that takes precedence into account.

Basic things

Next, we define the type Rule of rules as well as the list rules that contains all rules:

dataRule=R1|R2|R3|R4derivingShowrules :: [Rule]
rules = [R1,R2,R3,R4]

Rule application

We first introduce a helper function that takes a string and returns the list of all splits of this string. Thereby, a split of a string str is a pair of strings str1 and str2 such that str1 ++ str2 == str. A straightforward implementation of splitting is as follows:

splits' ::Str-> [(Str,Str)]
splits' str =zip (inits str) (tails str)

The problem with this implementation is that walking through the result list takes quadratic time, even if the elements of the list are left unevaluated. The following implementation solves this problem:

We are now ready to implement the function apply, which performs rule application. This function takes a rule and a string and produces all strings that can be derived from the given string using the given rule exactly once.

Now we implement a function derivs that converts a derivation tree into the list of all derivations that start with the tree’s root label. The function derivs traverses the tree in breadth-first order.

Prerequisites

The example code in this article needs support for the Constraint kind, of course. So we have to enable the appropriate language extension (which is surprisingly called ConstraintKinds instead of ConstraintKind). Furthermore, we want to make use of type families. All in all, this leads to the following LANGUAGE pragma:

{-# LANGUAGE ConstraintKinds, TypeFamilies #-}

We will define our own version of the Monad class. Therefore, we have to hide the Monad class from the Prelude:

importPreludehiding (Monad (..))

We will need the module Data.Set from the containers package for some example code:

importData.Set

Last, but not least, we have to import the kind Constraint:

importGHC.Exts (Constraint)

The general picture

Originally, classes and contexts were not first-class citizens in Haskell. The introduction of the Constraint kind has changed this. Classes and contexts can now be used as parameters of types, for example. This is because they are now types themselves.

However, classes and contexts are still not types in the strict sense. There are still no values of type Eq or Eq Integer, for example. As I have explained in my previous post, Haskell’s notion of type is more general than the usual one. In particular, functions on types are types themselves. However, they are not types of kind *. The same holds for classes and contexts. They are not types of kind *, but they are types of some other kinds, so that they can generally be used in places where types can be used.

The new kind Constraint, which is exported by GHC.Exts, is the kind of all contexts. Classes and contexts are now handled as follows:

Each class with parameters of kinds k_1 through k_n is a type of kind k_1 -> k_n -> Constraint.

Each tuple type (t_1, ..., t_n) where t_1 through t_n are of kind Constraint is also of kind Constraint and denotes the conjunction of t_1 through t_n. As a corner case, the nullary tuple type () is also of type Constraint and denotes the constraint that is always true.

A context can be any type of kind Constraint.

These rules guarantee that classes and contexts can be used as before. For example, (Read val, Show val) is still a context, because Read and Show are types of kind * -> Constraint, so Read val and Show val are types of kind Constraint, and therefore (Read val, Show val) is a type of kind Constraint.

However, classes and constraints can be used in new ways now. Here are some examples:

Classes can be partially applied, and the results can be used like classes again.

Classes, partially applied classes, and contexts can be parameters of types and instances of classes.

Aliases of classes, partially applied classes, and contexts can be defined using type declarations.

Families of classes, partially applied classes, and contexts can be defined using type synonym families.

In the remainder of this article, I will illustrate the last two of these points.

Context aliases

Sometimes, the same conjunction of several contexts appears in multiple types. In such cases, it can become cumbersome to always write these conjunctions explicitly. For example, there might be several functions in a library that deal with values that can be turned into strings and generated from strings. In this case, the types of these functions will typically have a context that contains constraints Show val and Read val. With the Constraint kind, we can define context aliases Text val as follows:

typeText val = (Show val, Read val)

Instead of Show val, Read val, we can now simply write Text val in contexts.

A few years ago, there was an attempt to implement support for context aliases (often called class aliases) in GHC. With the Constraint kind, this is now obsolete, as context aliases are now just a special kind of type aliases.

Context families

We will illustrate the use of context families by defining a generalized version of the Monad class.

The actual definition of a monad from category theory says that a monad on a category 𝒞 consists of an endofunctor on 𝒞 and some natural transformations. In Haskell, however, a monad is defined to be an instance of the Monad class, which contains the two methods return and (>>=). Haskell monads are monads on the category Hask, the category of kind-* types and functions.

There are monads in the category theory sense that are almost monads in the Haskell sense, but not quite. One example is the monad behind Haskell’s Set type. There are reasonable implementations of return and (>>=) for Set:

The problem is that the type of setBind is too restrictive, as it restricts the choice of element types by a context, whereas there is no such restriction in the type of (>>=). The reason for the restriction on element types is that the Set monad is not a monad on the category Hask, but on the full subcategory of Hask whose objects are the instances of Ord.

Using context families, we can generalize the Monad class such that restrictions on the type parameters of Monad instances become possible. We introduce a type synonym family Object such that Object mon val is the constraint that the parameter val must fulfill when working with the Monad instance mon. We provide a default definition for Object that does not restrict monad parameters. Finally, we change the types of return and (>>=) such that they restrict their Monad instance parameters accordingly. The new declaration of the Monad class is as follows:

We can make every instance of the original Monad class an instance of our new Monad class. Because of the default definition of Object, we do not need to define Object in these cases. So the instance declarations can look exactly like those for the original Monad class. Here is an example for the [] type:

In this article, I will present several of Haskell’s type system features. Some of them belong to the standard, others are only available as extensions. This is a write-up of a talk I gave on 31 January 2013 during the Theory Lunch of the Institute of Cybernetics. This talk provided the basics for another Theory Lunch talk, which was about the Constraint kind.

This whole article was written as a literate Haskell file with ordinary text written in Markdown. You can download this literate Haskell file, read it, and load it into GHCi to play with the code. The HTML for the blog post was generated using Pandoc.

Prerequisites

We first enable some language extensions that we will use in this article:

{-# LANGUAGE MultiParamTypeClasses, TypeFamilies #-}

We will reimplement some bits of the Prelude for illustration purposes, and we will use functions from other modules whose names clash with those of certain Prelude functions. Therefore, we have to hide parts of the Prelude:

These imports require the packages Stream, natural-numbers, and containers to be installed.

Kinds

Types typically denote sets of values. For example, Integer denotes the set of all integers, Char denotes the set of all characters, and [Bool] denotes the set of all truth value lists.

However, Haskell uses a more general notion of type, which also covers functions on types. So for example, the unapplied list type constructor [] is also considered a type, as is a partial application of the function type constructor like (->) Integer. Clearly, these types do not contain values.

To distinguish between ordinary types and functions on types, Haskell uses a system of kinds. Kinds are the “types of types”, so to say. A kind is either * or has the form kind1 -> kind2, where kind1 and kind2 are again kinds. The kind * is the kind of all ordinary types (that is, types that contain values), and a kind1 -> kind2 is the kind of all type-level functions from kind1 to kind2. Following are some examples of types and their kinds:

Integer, Char, [Bool], [[Bool]], [val] :: *

[], Maybe :: * -> *

Note that in a kind kind1 -> kind2, kind1 and kind2 can be kinds of function types again. So higher-order types are possible. As a result, type functions with several arguments can be implemented by means of Currying. For example, Haskell’s pair type and function type constructors are kinded as follows:

(,), (->) :: * -> * -> *

Furthermore, we can have type constructors with type function arguments. Take the following generic types of trees and forests as an example:

The Identity type used in the definition of Stream is defined as follows:

newtypeIdentity val =Identity val

I also want to mention that if we have a type Event in functional reactive programming, Tree Event is the type of behaviors that change only at discrete times, and Forest Event is the type of event streams.

Type classes

A type class denotes a set of types, which are called the instances of the class. Each class declares a set of methods that its instances have to implement.

Simple type classes

As an example of a type class, let us partially reimplement the Eq class from the Prelude, whose methods are (==) and (/=):

classEq val where
(==), (/=) :: val -> val ->Bool

Eq is supposed to cover all types whose values can be checked for equality. Here is an instance declaration for the Bool type:

Constructor classes

It is possible to define classes whose instances have a kind other than *. These are sometimes called constructor classes. An example of such a class is the Functor class from the Prelude, whose instances have kind * -> *. Here is a reimplementation:

Note that these instance declarations make the specialized versions of Tree and Forest that we have defined above automatically instances of Functor.

Multi-parameter type classes

GHC allows classes to have multiple parameters. While single-parameter classes denote sets of types, multi-parameter classes denote relations between types. An example of a class with two parameters is the class that relates types for which there is a conversion function:

classConvertible val val' where convert :: val -> val'

We can convert from type Int to type Integer, but also between types Int and Char:

Type families

Haskell allows us to define new types using data declarations. An example of such a declaration is the following one, which introduces a type of lists:

dataList el =Nil|Cons el (List el)

Furthermore, we can use type declarations for defining aliases of existing types. For example, we can use the following type declaration to define types of functions whose domain and codomain are the same:

typeEndo val = val -> val

Both data and type declarations have in common that the types they define are parametric. Informally speaking, this means that the basic structure of the defined types is independent of type parameters. For example, lists are always either empty or pairs of an element and another list, no matter what the element type is. The choice of an el parameter only determines the structure of elements. Likewise, values of a type Endo val are always functions whose domain and codomain are the same. The val parameter just determines the concrete domain and codomain type in use.

There are situations, however, where we want to define type-level functions that yield completely differently structured types for different arguments. This is possible with the type family extension that GHC provides.

There exist two flavors of type families: data families and type synonym families. Data families introduce new types and use the data keyword, while type synonym families define aliases for types and use the type keyword. This is analogous to data and type declarations, respectively. Type families can be stand-alone or associated. The former variant is analogous to top-level functions, while the latter is analogous to class methods. We will only deal with the latter in this post.

Data families

As an example of a data family, we define a type of total maps, that is, maps that assign values to every value of a chosen key type. Essential to our definition is that different key types lead to differently structured maps. We declare a class of key types, which contains the data family for total maps:

Let us now give an instance declaration for Bool. Total maps with boolean keys are essentially pairs of values, consisting of one value for the False key and one value for the True key. Our instance declaration reflects this:

More advanced things are possible. For example, pairs of keys can again serve as keys. A total map of a type TotalMap (key1,key2) val corresponds to a function of type (key1,key2) -> val, which in turn corresponds to a function of type key1 -> key2 -> val. This suggests how to implement total maps with pair keys:

Type synonym families

Let us now look at an example of a type synonym family. We define a class of collection types where a collection is basically anything that contains elements. Here are two examples of collection types:

Set el for any type el that is an instance of Ord

IntSet

Our class contains a type synonym family that tells for every collection type what the corresponding type of collection elements is. The class declaration is as follows:

Temporal logic and FRP are connected via a Curry–Howard correspondence. Thereby the “always” modality corresponds to the type constructor for behaviors, and the “eventually” modality corresponds to the type constructor for events. However there are more temporal operators. One example is the “until” operator from LTL. The paper shows that a proof of an “until” proposition can be regarded as an FRP value that consists of a finite time-varying value and a terminal event. I call such a value a process. It has turned out that processes are a really useful concept for reactive programming, in particular, when they are combined with recursion. The paper gives several examples of their use.

Causality in categorical models of FRP

In Section 2 of my MFPS paper, I presented a rather simple categorical semantics for temporal logic and FRP, which directly expresses time-dependence of trueness in temporal logic and of type inhabitance in FRP. However this semantics also models noncausal FRP operations, which actually cannot occur in real life. The new paper presents an improved version of the simple categorical semantics that takes causality into account. Its key idea is to deal with the time-dependent knowledge about values instead of the values themselves.