1 of 113

Glance’s compact visual syntax for Haskell

Making visual programming scale

1

2 of 113

Goal

2

Computing for everyone.

3 of 113

Visual programming

3

Popular for domain specific programming

  • Music (Max)
  • Video games (Blueprints in Unreal Engine)
  • Test equipment (LabVIEW)

4 of 113

Visual programming

4

Not popular for general purpose programming.

5 of 113

Visual programming

5

“The most common complaint from people who have actually tried visual programming is that it works well in the small, but becomes untenable past a certain complexity threshold.”

  • Ivan Reese

https://github.com/ivanreese/visual-programming-codex/blob/master/criticisms.md

6 of 113

The question

6

Can visual programming scale to large programs and systems?

7 of 113

What’s needed

7

A visual representation of code that is

  • compact
  • easy to read

8 of 113

The plan

8

  1. Experiment with visual representations of Haskell
  2. Design a compact and easy to read visual representation of Haskell (this presentation).
  3. Implement a visual editor for a subset of Haskell where the inputs and outputs of the editor are textual Haskell files.
  4. Create large programs and computing systems using the visual editor.

9 of 113

Key idea

9

Graphical, structured, and textual code representations are but points on a smooth continuum.

10 of 113

Quick overview (5 minutes)

10

11 of 113

Nodes

11

main = do

putStrLn “Name:”

name <- getLine

putStrLn name

f x

y

y = f x

(\x -> x)

λ

x

f

Right 3

Left

x

Right

x

comparisonString = if

x > 3 -> “greater than 3”

x < 7 -> “less than 7”

y

> 3

x

“greater than 3”

< 7

“less than 7”

comparisonString

y = case (f (Right 3) of

Left x -> x

Right x -> x

putStrLn

getLine

putStrLn “Name:”

main

Apply a function

Define a function

12 of 113

Wires

12

4

x

4

x

show

  • 2 5
  • 2 5

show

λ

z

y

x

makePosition

λ

z

y

x

makePosition

Position

sum

1

4

3

2

λ

y

x

λ

w

λ

z

y

x

makePosition

x

y

z

Position

Position

Bundles

Child bundles

Tunnels

Signposts

Funnels

13 of 113

FizzBuzz

13

== 0

λ

x

“FizzBuzz”

mod 15

x

traverse_ putStrLN

fmap

enumFromTo 1 100

“Fizz”

“Buzz”

show

main

== 0

== 0

mod 3

x

mod 5

x

x

14 of 113

Factorial

14

*

λ

x

1

> 0

x

- 1

x

x

λ

15 of 113

makeAsBindGraph

15

bindsToSyntaxGraph

mapMaybe

mName

Just

SgBind

λ

Just

asName

Nothing

makeBind

λ

ref

asNames

ref

asNames

makeAsBindGraph

16 of 113

Key Idea

16

Graphical, structured, and textual code representations are but points on a smooth continuum.

17 of 113

Factorial

17

*

λ

x

1

- 1

λ

> 0

Graphical

Textual

18 of 113

Factorial

18

*

λ

x

1

- 1

λ

> 0

Graphical

Textual

19 of 113

Factorial

19

*

λ

x

1

- 1

λ

> 0

Graphical

Textual

20 of 113

Factorial

20

*

λ

x

1

- 1

λ

> 0

Graphical

Textual

21 of 113

Factorial

21

*

λ

x

1

> 0

x

- 1

x

x

λ

Graphical

Textual

22 of 113

Factorial

22

*

λ

x

1

> 0

x

- 1

x

x

λ

Graphical

Textual

23 of 113

Factorial

23

*

λ

x

1

> 0

x

- 1

x

λ

x

Graphical

Textual

24 of 113

Factorial

24

*

λ

x

1

> 0

x

- 1

x

x

fact

fact

Graphical

Textual

25 of 113

Factorial

25

*

fact x

λ

1

> 0

x

- 1

x

x

fact

Graphical

Textual

26 of 113

Factorial

26

*

fact x

λ

1

> 0

x

- 1

x

x

fact

Graphical

Textual

27 of 113

Factorial

27

*

fact x

λ

1

> 0

x

- 1

x

x

fact

Graphical

Textual

28 of 113

Factorial

28

If

then

else

*

fact x

λ

1

> 0

x

- 1

x

x

fact

Graphical

Textual

29 of 113

Factorial

29

If (> 0 x)

then (* x (fact (- x 1)))

else 1

fact x

λ

Graphical

Textual

30 of 113

Factorial

30

If (> 0 x)

then (* x (fact (- x 1)))

else 1

fact x =

Graphical

Textual

31 of 113

Factorial

31

If (> 0 x)

then (* x (fact (- x 1)))

else 1

fact x =

Graphical

Textual

32 of 113

Get involved!

  • Email me! Robbie Gleichman, rgleichman@gmail.com
  • Pair program! (No Haskell knowledge required)
  • Make bugs on GitHub! https://github.com/rgleichman/glance
    • Need advice on making Haskell GUIs

32

This presentation is licensed under Creative Commons Attribution 4.0

33 of 113

The syntax in depth

33

34 of 113

Design strategies

34

  • Overlapping and embedded nodes
  • Indentation based grouping
  • Reducing the number of wires
  • Similar to Haskell textual syntax

35 of 113

Function application

35

f x

y

y = f x

y = f x1 x2

f x1 x2

y

f

y

x

y

x

f

x2 x1 f

y

36 of 113

Function definition

36

(\x -> x)

λ

x

λ

x

37 of 113

Function definition

37

f x = ...

....

λ

x

38 of 113

Function definition

38

compose f g x

= f (g x)

λ

x

g

f

compose

39 of 113

Applying a defined function

39

compose f g x

= f (g x)

thriceSquared

= compose (^2) (*3)

λ

x

g

f

thriceSquared

^2

*3

compose

40 of 113

Applying a defined function

40

compose f g x = f (g x)

thriceSquared

= compose (^2) (*3)

λ

x

g

f

thriceSquared

^2

*3

compose

41 of 113

Applying a defined function

41

13

λ

x

g

f

thriceThirteenSquared

^2

*3

compose

42 of 113

Reductions steps

1. Replace parameters

with arguments.

42

13

λ

^2

*3

13

thriceThirteenSquared

^2

*3

43 of 113

Reductions steps

1. Replace parameters

with arguments. (cont)

43

13

^2

*3

^2

*3

13

λ

^2

*3

thriceThirteenSquared

44 of 113

Reductions steps

2. Shrink the lambda.

44

13

thriceSquared

^2

*3

^2

*3

λ

thriceThirteenSquared

45 of 113

Reductions steps

3. Remove the function application.

45

13

^2

*3

λ

thriceThirteenSquared

46 of 113

Reductions steps

4. Remove the lambda with no parameters.

46

13

^2

*3

thriceThirteenSquared

47 of 113

Reductions steps

4. Remove the lambda with no parameters. (cont)

47

13

^2

*3

thriceThirteenSquared

48 of 113

Case

48

f

Right 3

Left

x

Right

x

f

Right 3

Left

x

Right

x

y = case (f (Right 3) of

Left x -> x

Right x -> x

y

y

49 of 113

Case

49

y = case (f (Right 3) of

Left x -> x

Right x -> x

f

Right 3

Left

x

Right

x

y

50 of 113

If / Guard

50

> 3

4

“greater than 3”

< 7

“less than 7”

comparisonString

> 3

4

“greater than 3”

< 7

“less than 7”

comparisonString

comparisonString = if

x > 3 -> “greater than 3”

x < 7 -> “less than 7”

51 of 113

If / Guard

51

> 3

4

“greater than 3”

< 7

“less than 7”

comparisonString

N125LT

52 of 113

Chaining (If / Guard) into a function application

52

++ “Four is “

comparisonString

> 3

4

“greater than 3”

< 7

“less than 7”

53 of 113

Do notation

53

putStrLn

++

getLine

putStrLn “Enter first line”

getLine

putStrLN “Enter second line”

main

54 of 113

(x = 4)

No tunneling

Tunneling

54

4

x

4

x

55 of 113

Tunneling into an expression

55

putStrLn

show

4

putStrLn

show

56 of 113

Tunneling into an if

56

> 3

4

“greater than 3”

< 7

“less than 7”

comparisonString

57 of 113

Short connections use a funnel to avoid line crossings

No funnel

Funnel

57

++

show

  • 2 5

“sum =”

++

  • 2 5

“sum =”

show

58 of 113

Short connections use a funnel to avoid line crossings

No funnel

Funnel

58

++

show

  • 2 5

“sum =”

++

  • 2 5

“sum =”

show

59 of 113

Signposts point towards the other end of the line

59

sum

1

4

3

2

60 of 113

Without signposts you have to follow the lines

60

sum

4

2

3

1

61 of 113

No lines?

61

sum

3

1

4

2

62 of 113

Multiple signs

62

1

sum

63 of 113

Signpost example

63

++

show

  • 2 5

“sum =”

64 of 113

A simple function

64

λ

z

y

x

makePosition

Position

65 of 113

Bundles

65

λ

z

y

x

makePosition

Position

66 of 113

Bundles

66

λ

z

y

x

makePosition

Position

67 of 113

Bundles

67

λ

z

y

x

makePosition

Position

68 of 113

Bundles

68

λ

z

y

x

makePosition

Position

69 of 113

Bundles

69

λ

z

y

x

makePosition

Position

Position

makePosition x y z = Position x y z

λ

z

y

x

makePosition

λ

z

y

x

makePosition

Position

70 of 113

Unbundling

70

λ

z

y

x

makePosition

Position

x

y

z

71 of 113

Child bundles

71

λ

z

y

x

makePosition

Position

λ

w

72 of 113

Examples

72

73 of 113

FizzBuzz

73

== 0

λ

x

“FizzBuzz”

mod 15

x

traverse_ putStrLN

fmap

enumFromTo 1 100

“Fizz”

“Buzz”

show

x

main

== 0

mod 3

x

== 0

mod 5

x

74 of 113

FizzBuzz

74

== 0

λ

x

“FizzBuzz”

mod 15

x

traverse_ putStrLN

fmap

enumFromTo 1 100

“Fizz”

“Buzz”

show

main

== 0

== 0

mod 3

x

mod 5

x

x

75 of 113

FizzBuzz

75

fizz n | n `mod` 15 == 0 = "FizzBuzz"

| n `mod` 3 == 0 = "Fizz"

| n `mod` 5 == 0 = "Buzz"

| otherwise = show n

main = traverse_ putStrLn (fmap fizz (enumFromTo 1 100))

76 of 113

Factorial

76

*

λ

x

1

> 0

x

- 1

x

x

λ

77 of 113

makeAsBindGraph

77

bindsToSyntaxGraph

mapMaybe

mName

Just

SgBind

λ

Just

asName

Nothing

makeBind

λ

ref

asNames

ref

asNames

makeAsBindGraph

78 of 113

makeAsBindGraph

78

makeAsBindGraph ref asNames

= bindsToSyntaxGraph $ mapMaybe makeBind asNames

where

makeBind mName = case mName of

Nothing -> Nothing

Just asName -> Just $ SgBind asName ref

79 of 113

makeAsBindGraph

79

bindsToSyntaxGraph

mapMaybe

mName

Just

SgBind

λ

Just

asName

Nothing

makeBind

λ

ref

asNames

ref

asNames

makeAsBindGraph

makeAsBindGraph ref asNames

= bindsToSyntaxGraph $ mapMaybe makeBind asNames

where

makeBind mName = case mName of

Nothing -> Nothing

Just asName -> Just $ SgBind asName ref

80 of 113

ASCII Art

80

$ref asNames <makeAsBindGraph>

| / $mName+ <makeBind>

| | &case * of

| #-+ Nothing ~% Nothing

| # Just asName------+

+ref--> ~% Just $ SgBind * (->)

+(asNames makeBind)=rev

&bindsToSyntaxGraph $ * mapMaybe

81 of 113

What about large functions?

81

82 of 113

Cheat!

82

83 of 113

Representation of connections

83

Distance from definition to usage

Visualness

84 of 113

Cheat by using names to refer to variables in large functions.

84

85 of 113

Which is done by using bundles and child bundles.

85

86 of 113

Child bundles

86

λ

z

y

x

makePosition

Position

λ

w

87 of 113

convertWithOpts :: Opt -> IO ()

convertWithOpts opts = do

let outputFile = fromMaybe "-" (optOutputFile opts)

let filters = optFilters opts

let verbosity = optVerbosity opts

when (optDumpArgs opts) $

do UTF8.hPutStrLn stdout outputFile

mapM_ (UTF8.hPutStrLn stdout) (fromMaybe ["-"] $ optInputFiles opts)

exitSuccess

let isPandocCiteproc (JSONFilter f) = takeBaseName f == "pandoc-citeproc"

isPandocCiteproc _ = False

-- --bibliography implies -F pandoc-citeproc for backwards compatibility:

let needsCiteproc = isJust (lookupMeta "bibliography"

(optMetadata opts)) &&

optCiteMethod opts `notElem` [Natbib, Biblatex] &&

all (not . isPandocCiteproc) filters

let filters' = filters ++ [ JSONFilter "pandoc-citeproc" | needsCiteproc ]

let sources = case optInputFiles opts of

Nothing -> ["-"]

Just xs | optIgnoreArgs opts -> ["-"]

| otherwise -> xs

datadir <- case optDataDir opts of

Nothing -> do

ds <- defaultUserDataDirs

let selectUserDataDir [] = return Nothing

selectUserDataDir (dir:dirs) = do

exists <- doesDirectoryExist dir

if exists

then return (Just dir)

else selectUserDataDir dirs

selectUserDataDir ds

Just _ -> return $ optDataDir opts

let runIO' :: PandocIO a -> IO a

runIO' f = do

(res, reports) <- runIOorExplode $ do

setTrace (optTrace opts)

setVerbosity verbosity

x <- f

rs <- getLog

return (x, rs)

case optLogFile opts of

Nothing -> return ()

Just logfile -> BL.writeFile logfile (encodeLogMessages reports)

let isWarning msg = messageVerbosity msg == WARNING

when (optFailIfWarnings opts && any isWarning reports) $

E.throwIO PandocFailOnWarningError

return res

let eol = case optEol opts of

CRLF -> IO.CRLF

LF -> IO.LF

Native -> nativeNewline

88 of 113

89 of 113

Glance goes here........

90 of 113

The coding continuum

90

Graphical, structured, and textual code representations are but points on a smooth continuum.

91 of 113

Factorial

91

*

λ

x

1

- 1

λ

> 0

Graphical

Textual

92 of 113

Factorial

92

*

λ

x

1

- 1

λ

> 0

Graphical

Textual

93 of 113

Factorial

93

*

λ

x

1

- 1

λ

> 0

Graphical

Textual

94 of 113

Factorial

94

*

λ

x

1

- 1

λ

> 0

Graphical

Textual

95 of 113

Factorial

95

*

λ

x

1

> 0

x

- 1

x

x

λ

Graphical

Textual

96 of 113

Factorial

96

*

λ

x

1

> 0

x

- 1

x

x

λ

Graphical

Textual

97 of 113

Factorial

97

*

λ

x

1

> 0

x

- 1

x

λ

x

Graphical

Textual

98 of 113

Factorial

98

*

λ

x

1

> 0

x

- 1

x

x

fact

fact

Graphical

Textual

99 of 113

Factorial

99

*

fact x

λ

1

> 0

x

- 1

x

x

fact

Graphical

Textual

100 of 113

Factorial

100

*

fact x

λ

1

> 0

x

- 1

x

x

fact

Graphical

Textual

101 of 113

Factorial

101

*

fact x

λ

1

> 0

x

- 1

x

x

fact

Graphical

Textual

102 of 113

Factorial

102

If

then

else

*

fact x

λ

1

> 0

x

- 1

x

x

fact

Graphical

Textual

103 of 113

Factorial

103

If (> 0 x)

then (* x (fact (- x 1)))

else 1

fact x

λ

Graphical

Textual

104 of 113

Factorial

104

If (> 0 x)

then (* x (fact (- x 1)))

else 1

fact x =

Graphical

Textual

105 of 113

Factorial

105

If (> 0 x)

then (* x (fact (- x 1)))

else 1

fact x =

Graphical

Textual

106 of 113

Extra slides

106

107 of 113

Textual

Structured

Influences

Visual (node and wire)

  • Indentation
  • Whitespace
  • Top-to-bottom
  • Nested expressions
  • Visual connections between definitions and references

107

> 3

4

“greater than 3”

< 7

“less than 7”

comparisonString

putStrLn

show 3

++

show

  • 2 5

“sum =”

108 of 113

makeAsBindGraph

108

bindsToSyntaxGraph

mapMaybe

mName

Just

SgBind

λ

Just

asName

Nothing

makeBind

λ

ref

asNames

ref

asNames

makeAsBindGraph

109 of 113

ASCII Art

109

$ref asNames <makeAsBindGraph>

| / $mName+ <makeBind>

| | &case * of

| #-+ Nothing ~% Nothing

| # Just asName------+

+ref--> ~% Just $ SgBind * (->)

+(asNames makeBind)=rev

&bindsToSyntaxGraph $ * mapMaybe

110 of 113

Design alternatives

Thank you to Mariano Guerra, William Taysom, Joshua Horowitz, Garth Goldwater, Edward de Jong, Yair Chuchem, and the Future of Coding community for their feedback and encouragement.

110

== 0 (mod 15)

λ

x

“FizzBuzz”

x

traverse_ putStrLN (fmap (enumFromTo 1 100))

“Fizz”

“Buzz”

show

main

x

if

if

if

if

then

then

then

then

== 0 (mod 3)

x

== 0 (mod 5)

x

111 of 113

Bundles

111

λ

z

y

x

makePosition

Position

112 of 113

Next step

112

  • Design a compact and easy to read visual representation of Haskell (this presentation).
  • Implement a visual editor for a subset of Haskell where the inputs and outputs of the editor are textual Haskell files.
  • Create large programs and computing systems using the visual editor.

113 of 113

Get involved!

  • Email me! Robbie Gleichman, rgleichman@gmail.com
  • Pair program! (No Haskell knowledge required)
  • Make bugs on GitHub! https://github.com/rgleichman/glance
    • Need advice on making Haskell GUIs

113

This presentation is licensed under Creative Commons Attribution 4.0