• No se han encontrado resultados

IDENTIFICACION Y DESCRIPCION GENERICAS DE TEORIAS DE ENFOQUES EXISTENTES

In document Biblioteca UP Bonaterra (página 39-44)

In this paper we generalised and expanded our original Tonic idea. Any monadic program can now be statically visualized by Tonic. While dynamic visualization is currently mostly limited to iTasks, we have laid the foundation for dynamically visualizing any monadic program.

So far, we have extensively experimented with using Tonic for iTasks. Our approach of using type classes for defining how dynamic behaviour should be captured allows for an almost completely orthogonal implementation for iTasks; the core system only required very minimal changes. The biggest change was made to the way iTasks handles task IDs. These IDs are not generated deterministically, so we had to implement a form of stack-tracing in iTasks to capture which tasks had already been executed. Systems with deterministic identifiers will not have to resort to such measures.

Section 5.5.1 shows the results of experiments aimed at supporting dynamic blueprints for the IO monad. The fact that we can successfully generate these blueprints suggests that Tonic can be used in contexts other than iTasks as well. While this experimental Tonic viewer works reasonably well for simple IO pro- grams, it lacks many of the features shown in Section 5.4.5 and is not very user- friendly. In the future we want to expand this stand-alone viewer to the point where it can replace the built-in iTasks Tonic viewer.

5.7. DISCUSSION AND CONCLUSION

Complete iTasks Agnostisism

Even though we have made the Tonic compiler completely iTasks-agnostic, Tonic itself still is tied to iTasks by means of the iTask context restriction in the Blueprintand Contained classes. The iTask class is used to be able to generi- cally inspect values. Its presence in the classes means that, even when using Tonic for non-iTasks programs, we require an iTasks-specific class to be instantiated for all types that we want to inspect. Clean’s type-system, however, o↵ers no elegant solution to this problem. GHC in particular could solve this problem elegantly using its ConstraintKinds and TypeFamilies extensions, as shown in the code snippet in Figure 5.33. Here, the context restriction depends on the type of the Blueprintmonad.

class Monad m => Contained m where type CCtxt m a :: Constraint type CCtxt m a = ()

wrapFunApp :: CCtxt m a => (ModuleName, FuncName) -> ExprId -> m a -> m a

class Contained m => Blueprint m where type BpCtxt m a :: Constraint type BpCtxt m a = ()

wrapFunBody :: BpCtxt m a => ModuleName -> FuncName -> [(VarName, m ())] -> m a -> m a

wrapFunArg :: BpCtxt m a => String -> a -> m () instance Contained Task where

type CCtxt Task a = ITask a wrapFunApp =..

instance Blueprint Task where type BpCtxt Task a = ITask a wrapFunBody =..

wrapFunArg =..

instance Contained Maybe where wrapFunApp =..

Figure 5.33: GHC definition of Tonic type classes.

For Clean, we could require values to be serializable to JSON so we can display data as a set of key-value pairs. While this approach would generalise the Tonic classes in the short term, it limits the ways in which we can present the inspected values. For example, we can currently render interactive graphics in the Tonic inspector. A true solution would be to implement variable context restrictions in type classes in Clean, similar to GHC.

Portability

By generalising Tonic it becomes clear that it could be implemented in a context di↵erent from Clean as well. Acknowledging that GHC in particular o↵ers elegant solutions to improve Tonic’s type classes, it would be interesting to explore porting Tonic to GHC.

Dynamic Blueprint Modification

Tonic’s blueprints, whether static or dynamic, are currently read-only. We cannot influence the execution of programs or change a program’s implementation. In the future we would like to explore such possibilities.

Wrapping up

Tonic lays the foundation for a plethora of distinct but related tools. On the one hand, blueprints can be seen as automatic program documentation. Each time a program is compiled, its blueprints are generated as well, giving the program- mer up-to-date documentation for free. Furthermore, dynamic instances of these blueprints document the program’s dynamic behaviour. Due to the blueprint’s high level of abstraction, this free documentation can serve as the basis of com- munication between various project stakeholders as well, enabling rapid software development cycles. Whether Tonic succeeds in being a suitable communication tool is a subject for future work.

Another way to look at Tonic is as a graphical tracer and debugger. Dynamic blueprints trace the execution of the program, while Tonic’s inspection and fu- ture branch prediction capabilities add features desirable in a debugger. Even for programmers, having such information visualized may aid in understanding the be- haviour of the programs they have written better. It may also aid in constructing the required program faster or with less e↵ort.

Yet another avenue worth exploring is education. We are currently including blueprints in the lecture slides of functional programming courses. In our experi- ence, students struggle with the concept of monads, so we want to see if and how Tonic can reduce these problems.

Chapter 6

Towards the Layout of Things

When writing a user interface (UI), the layout of its elements play an important role. Programmers should be able to specify the layout of UIs in an intuitive way, while being able to separate the concern of laying out the UI from the rest of the software implementation. Ideally, the same layout language can be used in mul- tiple application domains, so the programmer only has to learn one set of layout concepts. In this chapter we introduce such a general-purpose layout language. We obtain this language by abstracting from a layout language we have introduced in previous work for declaratively defining Scalable Vector Graphics (SVG). We show that this abstract layout language can be instantiated for multiple domains: the SVG library by which the language is inspired, ncurses-based text-based user inter- faces, and iTasks. In all of these cases, a separation of concerns is maintained.

6.1

Introduction

Every user interface (UI) consists of a collection of possibly interactive UI elements. The layout of the UI can significantly influence the user experience. Being able to lay out appealing user interfaces is therefore important for user-facing software. Ideally, defining such UIs is easy to do for a programmer, and can be done while maintaining a separation of concerns from the business logic of a program.

In previous work [6], we have introduced a Scalable Vector Graphics [27] (SVG) library called Graphics.Scalable. With this library, one can create SVG images in a purely compositional way by combining basic SVG elements using a small set of layout combinators. Only three basic layouts were specified: collages, overlays, and grids. In a collage, each SVG element, which in turn may be a layout of SVG elements, is given an absolute position, while in an overlay the individual elements can be aligned relative to a parent container. A grid layout can be used to place SVG elements in rows and columns. The SVG library also features two derived layout combinators above en beside, which are defined as grids of 1 column and row, respectively.

Defining SVG images with these layout combinators turned out to be very practical. In fact, we also wanted to be able to express the layouts of our iTasks framework [83, 68] in the same terms. Rather than implementing a new layout language, we opted to abstract from our original layout language and use this ab- stract language to implement the layout combinators for both our SVG library and iTasks. At the same time, the new abstract layout language must also be powerful enough to capture other domains. This gave rise to the following questions. How should one specify the spatial layout of visual, possibly interactive, components in your program? How should one separate the concern of maintaining the life-cycle

of UI components from their chosen layout? How do you identify UI components? In this chapter we propose a general purpose solution to these challenges.

For application domains that provide direct access to the UI components, it suffices to instantiate the overloaded layout language. Many application domains do not provide direct access to their UI components, however. For instance, in most widget-based APIs the program must first call handle-returning actions and use the obtained handle values to control the life-cycle and layout of the created UI components. Thus, the concerns of creating UI components on one hand versus arranging their layout on the other hand is not well separated.

To still provide a separation of concerns, we introduce a way to perform pattern matching on a specific part of the structure of the program. An annotation func- tion is applied to this part, which takes an abstract representation of the program’s structure over which layout can be specified. Pattern matching on this abstract representation can then be used to identify individual user-interface components. The annotation function returns a layout definition containing some or all of the UI components. With this annotation approach, the specification of layout can be decoupled from the identification of UI components. Naturally, if the annotated program fragment is changed, the identification code must also be re-considered. However, provided that the collection of identified UI components remains iden- tical, this does not a↵ect the layout specification. This also holds the other way around: changing the layout specification does not a↵ect the identification code.

The proposed combination of overloaded layout language and function anno- tation works for completely di↵erent application domains. We demonstrate this with the following case studies:

1. The Graphics.Scalable library of iTasks is the obvious first candidate to consider because the overloaded layout language was derived from it. Be- cause it provides direct access to its UI components, scalable images, it suffices to instantiate the overloaded layout language.

2. The ncurses library1, available as a Haskell package2, is the second case.

With ncurses terminal-style “GUI” applications can be created. As with the previous case, ncurses provides direct access to the UI components, so it suf- fices to instantiate the overloaded layout language. However, the application domain is quite di↵erent as the programmer needs to divide the available screen estate to the appropriate UI components.

3. The third case is iTasks, but now we wish to arrange the layout of the automatically generated UIs of entire tasks and task compositions. This is an illustrative case of a domain in which the code annotation is required to identify the task UIs that need to be provided with a layout.

We have implemented the overloaded layout language in both Clean [87] and Haskell [81]. Both iTasks-related case studies are implemented in Clean, while the ncurses case is implemented in Haskell.

1https://www.gnu.org/software/ncurses/ncurses.html

In document Biblioteca UP Bonaterra (página 39-44)

Documento similar