27 research outputs found

    Categoral views on computations on trees (Extended abstract)

    Get PDF
    Computations on trees form a classical topic in computing. These computations can be described in terms of machines (typically called tree transducers), or in terms of functions. This paper focuses on three flavors of bottom-up computations, of increasing generality. It brings categorical clarity by identifying a category of tree transducers together with two different behavior functors. The first sends a tree transducer to a coKleisli or biKleisli map (describing the contribution of each local node in an input tree to the global transformation) and the second to a tree function (the global tree transformation). The first behavior functor has an adjoint realization functor, like in Goguen’s early work on automata. Further categorical structure, in the form of Hughes’s Arrows, appears in properly parameterized versions of these structures

    When is a container a comonad?

    Full text link
    Abbott, Altenkirch, Ghani and others have taught us that many parameterized datatypes (set functors) can be usefully analyzed via container representations in terms of a set of shapes and a set of positions in each shape. This paper builds on the observation that datatypes often carry additional structure that containers alone do not account for. We introduce directed containers to capture the common situation where every position in a data-structure determines another data-structure, informally, the sub-data-structure rooted by that position. Some natural examples are non-empty lists and node-labelled trees, and data-structures with a designated position (zippers). While containers denote set functors via a fully-faithful functor, directed containers interpret fully-faithfully into comonads. But more is true: every comonad whose underlying functor is a container is represented by a directed container. In fact, directed containers are the same as containers that are comonads. We also describe some constructions of directed containers. We have formalized our development in the dependently typed programming language Agda

    Categorical Foundations of Explainable AI

    Full text link
    Explainable AI (XAI) aims to address the human need for safe and reliable AI systems. However, numerous surveys emphasize the absence of a sound mathematical formalization of key XAI notions -- remarkably including the term ``\textit{explanation}'' which still lacks a precise definition. To bridge this gap, this paper presents the first mathematically rigorous definitions of key XAI notions and processes, using the well-funded formalism of Category theory. We show that our categorical framework allows to: (i) model existing learning schemes and architectures, (ii) formally define the term ``explanation'', (iii) establish a theoretical basis for XAI taxonomies, and (iv) analyze commonly overlooked aspects of explaining methods. As a consequence, our categorical framework promotes the ethical and secure deployment of AI technologies as it represents a significant step towards a sound theoretical foundation of explainable AI

    Extending monads with pattern matching

    Full text link
    Sequencing of effectful computations can be neatly captured using monads and elegantly written using do notation. In practice such monads often allow additional ways of composing computations, which have to be written explicitly using combinators. We identify joinads, an abstract notion of computation that is stronger than monads and captures many such ad-hoc extensions. In particular, joinads are monads with three additional operations: one of type m a → m b → m (a, b) captures various forms of parallel composition, one of type m a → m a → m a that is inspired by choice and one of type m a → m (m a) that captures aliasing of computations. Algebraically, the first two operations form a near-semiring with commutative multiplication. We introduce docase notation that can be viewed as a monadic version of case. Joinad laws imply various syntactic equivalences of programs written using docase that are analogous to equiva-lences about case. Examples of joinads that benefit from the nota-tion include speculative parallelism, waiting for a combination of user interface events, but also encoding of validation rules using the intersection of parsers

    Programming with implicit flows

    Get PDF
    Modern software differs significantly from traditional computer applications that mostly process reasonably small amounts of static input data-sets in batch mode. Modern software increasingly processes massive amounts of data, whereby it is also often the case that new input data is produced and/or existing data is modified on the fly. Consequently, programming models that facilitate the development of such software are emerging. What characterizes them is that data, respectively changes thereof, implicitly flow through computation modules. The software engineer declaratively defines computations as compositions of other computations without explicitly modeling how data should flow along dependency relations between data producer and data consumer modules, letting the runtime to automatically manage and optimize data flows. Keywords: Reactive programming, event, stream, big data, data-flow We have come a long way since the early computer systems which were painstakingly fed problem data-sets via punch cards. Computer systems have become much more convenient to interact with and are able to process much larger data-sets, which are kept in large-scale storage systems. However, computer systems are also much more commonly involved in processing of data that is produced or modified in an online fashion, as the program is executing, sometimes in a perpetual manner. This is particularly the case in applications which are specifically developed to react to real-world happenings such as temperature changes or other environmental cues captured through sensors. The last decade has thus seen the advent of abstractions and paradigms that support the development of reactive software. Central to such approaches is the concept of event which captures dynamic occurrences that trigger computations. Over the years, several steps have been made in this direction, including language-level support for events, continuous time-changing values (a.k.a. signals or behaviors), constraints, asynchronous execution and futures. The ever-increasing complexity of reactive applications has recently raised new interest around these abstractions. The new paradigm of reactive programming focuses on a more holistic view that demands for seamless integration of existing solutions, including constraints resolution to enforce functional dependencies, automatic updates of dependent values, and interoperability among different reactive abstractions such as signals and event streams. The goal is to raise the abstraction level: Rather than explicitly reifying events in the software, changes to values of variables are detected and propagated through programs by re-computing the values of all dependent variables implicitly, i.e., by the language runtime. Interestingly, a similar trend can be observed in recent big data analysis software. Not too long ago, such programs were typically perceived as resembling complex queries applied to very large yet static data-sets. A host of programming languages and models have been proposed for such programs. They mostly mix imperative and declarative traits to clearly expose the order of a non-cyclic computation network, and are centered on some form of data-structures conceptualizing the current state of computation. Despite improvements in running time of such analysis programs often due to parallel execution over powerful computation environments, their execution can still take sufficiently long to make repeated complete executions of the same program upon additions or changes to the underlying big data-sets prohibitively expensive. Consequently, recent improvements consist in enabling incremental computations, i.e., re-executing only those parts of queries that become invalid or incomplete by changes to analyzed data-sets. While reactive and big data analysis applications have little in common at first glance, we observe a shared trend in the respective programming models: they strive to capture what the computation ought to do, but not when (and how) it shall do so, as the data which is subject to the computation changes over time (thus we speak of "data-flows"). It is the execution engines and language runtimes that increasingly carry the burden of determining which parts of computations are affected by which fluctuations in the processed data. As it is unlikely that runtime systems can determine these things entirely on their own -at least in an efficient manner -or that such transparency would even serve the programmer, new abstractions are needed to capture such implicit flows in addition to underlying runtime support. In the following, we first overview the nature and origins of reactive programming and big data analysis and implicit flows 1 therein. Next, we briefly touch on the state of the art and open challenges towards a unified approach to programming with implicit flows. Unification makes sense not only because of the shared trend towards implicit flows. More importantly it helps coping with the complexity of software that increasingly combines features from both families of applications. Events and Reactive Programming Events are a common way for programmers to reason about significant conditions in the environment and in the execution of a program. Dedicated abstractions for events have been supported by some mainstream languages for a long time. For example, in C#, events can be defined as class attributes beside methods and fields and belong to a class' interface. Over the last few years, researchers have proposed increasingly sophisticated event models (cf. Box "Avanced programming with events"). The integration into the object-oriented (OO) programming model has been enhanced to extend OO concepts like inheritance to events and event handling. Early approaches like Java P S [2] implemented events as specific objects. In EScala [11] events are first-class entities. As in C#, they are object attributes just like methods and fields; their definition is subject to polymorphic access and late binding. Our investigations Events in isolation improve little over the observer design pattern. The difference becomes crucial when expressive operators for event combination are available to correlate events to define new (complex) events that capture high-level situations of interest. Advanced systems support operators to combine events with increasing levels of expressiveness. For example, the e 1 ||e 2 expression in EScala returns an event that fires when either e 1 or e 2 fires. Full-fledged embeddings of complex event processing like EventJava [3], or stream processing languages like SPL [5], support complex queries over event streams including time windows and joins. In parallel to the development of richer event models, other researchers focused on more inherent data-flow and changedriven solutions for reactive applications. These approaches have old roots. For example, the Garnet and Amulet graphical toolkits The fundamental concept in reactive languages is that programmers do not directly handle the control flow but the execution is driven by the implicit flow of data and the need to update values. Concretely, programmers specify constraints that express functional dependencies among values in the application, and the language runtime enforces these constraints without any further effort from the programmer. More recently, these approaches have inspired many embeddings of DSLs and functional constraints in existing (imperative) programming languages. The advantage of this solution is that programmers specify a functional dependency in an intuitive, declarative way. As a consequence, reactions are directly expressed, do not need to be inferred from the control flow, and can be easily composed. In practice, (continuous) time-changing values, a.k.a. signals, are not enough. The need for events (i.e., discrete timechanging values) is explained by two observations. (a) Events come from external phenomena that are inherently discrete, such as an interrupt or new data from a sensor. (b) Events are better suited for modeling certain behaviors: in principle a mouse click can be modeled as a boolean continuous time-changing value that switches to true when the mouse is clicked, but most programmers would rather think of a mouse click as an event. For this reason, existing reactive languages provide both signals and events. Reactive programming is an emerging trend and identifying the boundaries of this field is hard. However, the following principles seem valid in general. • Declarative style. Reactive behavior is defined in a direct, convenient, declarative style instead of encoding it in design patterns or through imperative updates of program state. Reactions are directly expressed and do not need to be encoded into the control flow of the program. • Composition. Abstractions allow for composition of more complex reactions. Traditional OO applications express reactions in callbacks that are executed when an observable changes. However, callbacks typically perform side effects to modify the state of the application but do not return a value. As a result, they are hard to combine. Instead, events can be combined through combinators, and signals can be combined directly into more complex reactive expressions. • Automation. In AOP, advices are triggered at points in the execution of the program (e.g., the end of a method call) that are referred to as join points. Join points can be seen as events that occur during the execution and treated uniformly with other events. For example, EScala before(method) and after(method) events are triggered before and after the execution of methods.Also, in event-based languages that integrate AOP features, programmers can refer to all events of a certain type, a feature that resembles AOP quantification. As an example of an expressive event system, we show a slice of a drawing application in EScala

    Combining Effects and Coeffects via Grading

    Get PDF
    This is the author accepted manuscript. It is currently under an indefinite embargo pending publication by the Association for Computing Machinery.Effects\textit{Effects} and coeffects\textit{coeffects} are two general, complementary aspects of program behaviour. They roughly correspond to computations which change the execution context (effects) versus computations which make demands on the context (coeffects). Effectful features include partiality, non-determinism, input-output, state, and exceptions. Coeffectful features include resource demands, variable access, notions of linearity, and data input requirements. The effectful or coeffectful behaviour of a program can be captured and described via type-based analyses, with fine grained information provided by monoidal effect annotations and semiring coeffects. Various recent work has proposed models for such typed calculi in terms of graded (strong) monads\textit{graded (strong) monads} for effects and graded (monoidal) comonads\textit{graded (monoidal) comonads} for coeffects. Effects and coeffects have been studied separately so far, but in practice many computations are both effectful and coeffectful, e.g., possibly throwing exceptions but with resource requirements. To remedy this, we introduce a new general calculus with a combined effect-coeffect system\textit{effect-coeffect system}. This can describe both the changes\textit{changes} and requirements\textit{requirements} that a program has on its context, as well as interactions between these effectful and coeffectful features of computation. The effect-coeffect system has a denotational model in terms of effect-graded monads and coeffect-graded comonads where interaction is expressed via the novel concept of graded distributive laws\textit{graded distributive laws}. This graded semantics unifies the syntactic type theory with the denotational model. We show that our calculus can be instantiated to describe in a natural way various different kinds of interaction between a program and its evaluation context.Orchard was supported by EPSRC grant EP/M026124/1 and EP/K011715/1 (whilst previously at Imperial College London), Katsumata by JSPS KAKENHI grant JP15K00014, Uustalu by Estonian Min. of Educ. and Res. grant IUT33-13 and Estonian Sci. Found. grant 9475. Gaboardi’s work was done in part while at the University of Dundee, UK supported by EPSRC grant EP/M022358/1

    A Notation for Comonads

    Get PDF
    The category-theoretic concept of a monad occurs widely as a design pattern for functional programming with effects. The utility and ubiquity of monads is such that some languages provide syntactic sugar for this pattern, further encouraging its use. We argue that comonads, the dual of monads, similarly provide a useful design pattern, capturing notions of context dependence. However, comonads remain relatively under-used compared to monads—due to a lack of knowledge of the design pattern along with the lack of accompanying simplifying syntax. We propose a lightweight syntax for comonads in Haskell, analogous to the do-notation for monads, and provide examples of its use. Via our notation, we also provide a tutorial on programming with comonads
    corecore