Glance’s compact visual syntax for Haskell
Making visual programming scale
1
Goal
2
Computing for everyone.
Visual programming
3
Popular for domain specific programming
Visual programming
4
Not popular for general purpose programming.
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.”
https://github.com/ivanreese/visual-programming-codex/blob/master/criticisms.md
The question
6
Can visual programming scale to large programs and systems?
What’s needed
7
A visual representation of code that is
The plan
8
Key idea
9
Graphical, structured, and textual code representations are but points on a smooth continuum.
Quick overview (5 minutes)
10
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
Wires
12
4
x
4
x
show
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
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
Factorial
14
*
λ
x
1
> 0
x
- 1
x
x
λ
makeAsBindGraph
15
bindsToSyntaxGraph
mapMaybe
mName
Just
SgBind
λ
Just
asName
Nothing
makeBind
λ
ref
asNames
ref
asNames
makeAsBindGraph
Key Idea
16
Graphical, structured, and textual code representations are but points on a smooth continuum.
Factorial
17
*
λ
x
1
- 1
λ
> 0
Graphical
Textual
Factorial
18
*
λ
x
1
- 1
λ
> 0
Graphical
Textual
Factorial
19
*
λ
x
1
- 1
λ
> 0
Graphical
Textual
Factorial
20
*
λ
x
1
- 1
λ
> 0
Graphical
Textual
Factorial
21
*
λ
x
1
> 0
x
- 1
x
x
λ
Graphical
Textual
Factorial
22
*
λ
x
1
> 0
x
- 1
x
x
λ
Graphical
Textual
Factorial
23
*
λ
x
1
> 0
x
- 1
x
λ
x
Graphical
Textual
Factorial
24
*
λ
x
1
> 0
x
- 1
x
x
fact
fact
Graphical
Textual
Factorial
25
*
fact x
λ
1
> 0
x
- 1
x
x
fact
Graphical
Textual
Factorial
26
*
fact x
λ
1
> 0
x
- 1
x
x
fact
Graphical
Textual
Factorial
27
*
fact x
λ
1
> 0
x
- 1
x
x
fact
Graphical
Textual
Factorial
28
If
then
else
*
fact x
λ
1
> 0
x
- 1
x
x
fact
Graphical
Textual
Factorial
29
If (> 0 x)
then (* x (fact (- x 1)))
else 1
fact x
λ
Graphical
Textual
Factorial
30
If (> 0 x)
then (* x (fact (- x 1)))
else 1
fact x =
Graphical
Textual
Factorial
31
If (> 0 x)
then (* x (fact (- x 1)))
else 1
fact x =
Graphical
Textual
Get involved!
32
This presentation is licensed under Creative Commons Attribution 4.0
The syntax in depth
33
Design strategies
34
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
Function definition
36
(\x -> x)
λ
x
λ
x
Function definition
37
f x = ...
....
λ
x
Function definition
38
compose f g x
= f (g x)
λ
x
g
f
compose
Applying a defined function
39
compose f g x
= f (g x)
thriceSquared
= compose (^2) (*3)
λ
x
g
f
thriceSquared
^2
*3
compose
Applying a defined function
40
compose f g x = f (g x)
thriceSquared
= compose (^2) (*3)
λ
x
g
f
thriceSquared
^2
*3
compose
Applying a defined function
41
13
λ
x
g
f
thriceThirteenSquared
^2
*3
compose
Reductions steps
1. Replace parameters
with arguments.
42
13
λ
^2
*3
13
thriceThirteenSquared
^2
*3
Reductions steps
1. Replace parameters
with arguments. (cont)
43
13
^2
*3
^2
*3
13
λ
^2
*3
thriceThirteenSquared
Reductions steps
2. Shrink the lambda.
44
13
thriceSquared
^2
*3
^2
*3
λ
thriceThirteenSquared
Reductions steps
3. Remove the function application.
45
13
^2
*3
λ
thriceThirteenSquared
Reductions steps
4. Remove the lambda with no parameters.
46
13
^2
*3
thriceThirteenSquared
Reductions steps
4. Remove the lambda with no parameters. (cont)
47
13
^2
*3
thriceThirteenSquared
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
Case
49
y = case (f (Right 3) of
Left x -> x
Right x -> x
f
Right 3
Left
x
Right
x
y
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”
If / Guard
51
> 3
4
“greater than 3”
< 7
“less than 7”
comparisonString
N125LT
Chaining (If / Guard) into a function application
52
++ “Four is “
comparisonString
> 3
4
“greater than 3”
< 7
“less than 7”
Do notation
53
putStrLn
++
getLine
putStrLn “Enter first line”
getLine
putStrLN “Enter second line”
main
(x = 4)
No tunneling
Tunneling
54
4
x
4
x
Tunneling into an expression
55
putStrLn
show
4
putStrLn
show
Tunneling into an if
56
> 3
4
“greater than 3”
< 7
“less than 7”
comparisonString
Short connections use a funnel to avoid line crossings
No funnel
Funnel
57
++
show
“sum =”
++
“sum =”
show
Short connections use a funnel to avoid line crossings
No funnel
Funnel
58
++
show
“sum =”
++
“sum =”
show
Signposts point towards the other end of the line
59
sum
1
4
3
2
Without signposts you have to follow the lines
60
sum
4
2
3
1
No lines?
61
sum
3
1
4
2
Multiple signs
62
1
sum
Signpost example
63
++
show
“sum =”
A simple function
64
λ
z
y
x
makePosition
Position
Bundles
65
λ
z
y
x
makePosition
Position
Bundles
66
λ
z
y
x
makePosition
Position
Bundles
67
λ
z
y
x
makePosition
Position
Bundles
68
λ
z
y
x
makePosition
Position
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
Unbundling
70
λ
z
y
x
makePosition
Position
x
y
z
Child bundles
71
λ
z
y
x
makePosition
Position
λ
w
Examples
72
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
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
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))
Factorial
76
*
λ
x
1
> 0
x
- 1
x
x
λ
makeAsBindGraph
77
bindsToSyntaxGraph
mapMaybe
mName
Just
SgBind
λ
Just
asName
Nothing
makeBind
λ
ref
asNames
ref
asNames
makeAsBindGraph
makeAsBindGraph
78
makeAsBindGraph ref asNames
= bindsToSyntaxGraph $ mapMaybe makeBind asNames
where
makeBind mName = case mName of
Nothing -> Nothing
Just asName -> Just $ SgBind asName ref
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
ASCII Art
80
$ref asNames <makeAsBindGraph>
| / $mName+ <makeBind>
| | &case * of
| #-+ Nothing ~% Nothing
| # Just asName------+
+ref--> ~% Just $ SgBind * (->)
+(asNames makeBind)=rev
&bindsToSyntaxGraph $ * mapMaybe
What about large functions?
81
Cheat!
82
Representation of connections
83
Distance from definition to usage
Visualness
Cheat by using names to refer to variables in large functions.
84
Which is done by using bundles and child bundles.
85
Child bundles
86
λ
z
y
x
makePosition
Position
λ
w
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
Glance goes here........
The coding continuum
90
Graphical, structured, and textual code representations are but points on a smooth continuum.
Factorial
91
*
λ
x
1
- 1
λ
> 0
Graphical
Textual
Factorial
92
*
λ
x
1
- 1
λ
> 0
Graphical
Textual
Factorial
93
*
λ
x
1
- 1
λ
> 0
Graphical
Textual
Factorial
94
*
λ
x
1
- 1
λ
> 0
Graphical
Textual
Factorial
95
*
λ
x
1
> 0
x
- 1
x
x
λ
Graphical
Textual
Factorial
96
*
λ
x
1
> 0
x
- 1
x
x
λ
Graphical
Textual
Factorial
97
*
λ
x
1
> 0
x
- 1
x
λ
x
Graphical
Textual
Factorial
98
*
λ
x
1
> 0
x
- 1
x
x
fact
fact
Graphical
Textual
Factorial
99
*
fact x
λ
1
> 0
x
- 1
x
x
fact
Graphical
Textual
Factorial
100
*
fact x
λ
1
> 0
x
- 1
x
x
fact
Graphical
Textual
Factorial
101
*
fact x
λ
1
> 0
x
- 1
x
x
fact
Graphical
Textual
Factorial
102
If
then
else
*
fact x
λ
1
> 0
x
- 1
x
x
fact
Graphical
Textual
Factorial
103
If (> 0 x)
then (* x (fact (- x 1)))
else 1
fact x
λ
Graphical
Textual
Factorial
104
If (> 0 x)
then (* x (fact (- x 1)))
else 1
fact x =
Graphical
Textual
Factorial
105
If (> 0 x)
then (* x (fact (- x 1)))
else 1
fact x =
Graphical
Textual
Extra slides
106
Textual
Structured
Influences
Visual (node and wire)
107
> 3
4
“greater than 3”
< 7
“less than 7”
comparisonString
putStrLn
show 3
++
show
“sum =”
makeAsBindGraph
108
bindsToSyntaxGraph
mapMaybe
mName
Just
SgBind
λ
Just
asName
Nothing
makeBind
λ
ref
asNames
ref
asNames
makeAsBindGraph
ASCII Art
109
$ref asNames <makeAsBindGraph>
| / $mName+ <makeBind>
| | &case * of
| #-+ Nothing ~% Nothing
| # Just asName------+
+ref--> ~% Just $ SgBind * (->)
+(asNames makeBind)=rev
&bindsToSyntaxGraph $ * mapMaybe
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
Bundles
111
λ
z
y
x
makePosition
Position
Next step
112
Get involved!
113
This presentation is licensed under Creative Commons Attribution 4.0