diff --git a/app/Icons.hs b/app/Icons.hs index 4101962..0878e94 100644 --- a/app/Icons.hs +++ b/app/Icons.hs @@ -175,16 +175,16 @@ resultPort :: SyntaxNode -> Port resultPort = const resultPortConst caseRhsPorts :: [Port] -caseRhsPorts = fmap Port [2,4..] +caseRhsPorts = fmap Port [3,5..] casePatternPorts :: [Port] -casePatternPorts = fmap Port [3,5..] +casePatternPorts = fmap Port [2,4..] guardRhsPorts :: [Port] -guardRhsPorts = caseRhsPorts +guardRhsPorts = casePatternPorts guardBoolPorts :: [Port] -guardBoolPorts = casePatternPorts +guardBoolPorts = caseRhsPorts argumentPorts :: SyntaxNode -> [Port] argumentPorts n = case n of diff --git a/examples/tutorial.hs b/examples/tutorial.hs index 2f98074..289e024 100644 --- a/examples/tutorial.hs +++ b/examples/tutorial.hs @@ -5,6 +5,12 @@ How could it be extended? I feel that we are just at the very beginning of visual programming languages, and that there is a huge universe of visual programming language designs waiting to be discovered. +This tutorial assumes that the reader has some familiarity with the basics +of Haskell. + + +Function Application: + Let's start with y = f x. The function f is applied to the argument x, and the result is bound to y. -} @@ -39,7 +45,13 @@ y = (*) ((+) 8 7) 2 -} y = (*) ((+) 8 7) 2 -{-That was probably not too surprising. How about this?-} +{- + +The Mystery Icon: + +That was probably not too surprising. How about this? What does the green icon +represent? +-} f x = 3 * x {-Let's try to figure it out. First look at the f. It's green and in an orange @@ -59,7 +71,7 @@ y = (\x -> 3 * x) 7 {-Now for the answer. As you might have suspected. The green icon defines a function. The dot inside the icon is the formal parameter. The blue square -represents the value returned by function (i.e. what's on the right size +represents the value returned by function (i.e. what's on the right side of the -> in a lambda expression). The green circle represents the function that has been defined. @@ -129,7 +141,11 @@ f x y = max (2 * y) (1 + x) -} f x y = max (2 * y) (1 + x) -{-Something different about Glance is that Glance does not have any rigid code regions. +{- + +No Code Regions: + +Something different about Glance is that Glance does not have any rigid code regions. In other visual programming languages, the icons inside the body of a function would be restricted to a rectangle. In Glance, all icons are on the same level. Theoretically, Glance's flat layout should allow more compact drawings since space @@ -153,8 +169,11 @@ f1 x y = (\z -> x + z) y f1 x y = (\z -> x + z) y {- + +Graph and Tree Topology: + Let's go back to the function apply icon. If you are used to other graphical -programming languages, you may be thinking that drawing below +programming languages, you may be thinking that the drawing below does not look very graphical. Here graphical is referring to a graph topology, and no it does not look graphical. The core idea is that nested function application has a tree topology, not a graph topology. The result of each @@ -181,13 +200,16 @@ y = (((2 + 4 * 4) - (7+ 2 + baz)*8)/21) -} y = (((2 + 4 * 4) - (7+ 2 + baz)*8)/21) -{-Continuing on, here is a simple pattern match. +{- +Patterns: + +Continuing on, here is a simple pattern match. (Just x) = Just 3 -} (Just x) = Just 3 {- -Since constructors are functions, the match icon has a topology similar to +Since data constructors are functions, the match icon has a topology similar to the apply icon. Now that you are familiar with matches, here's a simple case expression. @@ -200,19 +222,17 @@ y = case maybeInt of Just x -> x + 1 {-The case icon is the magenta icon with three yellow circles next to it. -The matches (the textual part left of the arrow) connect to the triangles, -and the result for each match (the textual part to the right of the arrow) is -indicated with the yellow circle. +The patterns connect to the triangles, and the result for each match is indicated +with the yellow circle. The result for the first match (Nothing -> 0) connects to the circle on the case icon since the right hand side (0) does not use any value from the pattern (Nothing). For the second match, since the result (x + 1) is connected to its pattern (Just x), Glance can connect -the result to a new yellow circle. +the result of (x + 1) to a new yellow circle. -If the result always had to be connected to -the yellow result circle on the case icon, this would create many cycles in the -graph, making the layout much messier. + +Guards: Guards and if expressions look like this: y | x == 0 = 1 @@ -241,11 +261,13 @@ factorial x = then 1 else factorial (x - 1) * x -{-Bonus section: +{- +Compose (bonus section): The depth of an icon's application tree is called the nesting depth. For example, The icon representing "factorial (x - 1) * x" above has a nesting -depth of 3. +depth of 3, since it is an apply icon (depth=1), inside an apply icon (depth=2), +inside an apply icon (depth=3). To reduce nesting depth, Glance has an icon that represents an argument applied to a composition of functions. diff --git a/examples/tutorial.svg b/examples/tutorial.svg index d0d24a3..7f2e0d1 100644 --- a/examples/tutorial.svg +++ b/examples/tutorial.svg @@ -1,3 +1,3 @@ factorial*-110==factorial*-110== else x * factorial (x - 1) then 1 if x == 0factorial x =Notice that the nesting depth has been reduced from 3 to 2.(x *) . factorial . (x -) $ 1Glance essentially rewrites the second expression as:x * factorial (x - 1)tofactorial (x - 1) * xTo enable the compose icon, we change the expressionuses a compose icon for the else expression.For example, if we slightly rewrite the factorial function above, Glancereduce the nesting depth.Glance figures out automatically when to use the compose icon in order toyfghxyfghxy = (f . g . h) xwhich is the same asy = f (g (h x))With a composition of three functions:yfgxyfgxy = (f . g) xwhich is the same asy = f (g x)For example:to a composition of functions.To reduce nesting depth, Glance has an icon that represents an argument applieddepth of 3.For example, The icon representing "factorial (x - 1) * x" above has a nestingThe depth of an icon's application tree is called the nesting depth.Bonus section:factorial1-*10==factorial1-*10== else factorial (x - 1) * x then 1 if x == 0factorial x ="If" expressions are rendered the same as a guard with only one Boolean.topology, but they should look less similar in better icon versions.Currently, the guard icon and the case icon look similar since they have similarto the bottom of the mid-line.other side of the mid-line. The overall result that the guard is bound to connectscorresponding result expressions (e.g. x + 1) connect to the triangles on theThe Boolean expressions (e.g. x == 0) connect to the orange Ls, and they1x+otherwise10x==y1x+otherwise10x== | otherwise = x + 1y | x == 0 = 1Guards and if expressions look like this:graph, making the layout much messier.the yellow result circle on the case icon, this would create many cycles in theIf the result always had to be connected tothe result to a new yellow circle.(x + 1) is connected to its pattern (Just x), Glance can connectuse any value from the pattern (Nothing). For the second match, since the resultconnects to the circle on the case icon since the right hand side (0) does notThe result for the first match (Nothing -> 0)indicated with the yellow circle.and the result for each match (the textual part to the right of the arrow) isThe matches (the textual part left of the arrow) connect to the triangles,The case icon is the magenta icon with three yellow circles next to it.y1+Just0NothingmaybeInty1+Just0NothingmaybeInt Just x -> x + 1 Nothing -> 0y = case maybeInt ofNow that you are familiar with matches, here's a simple case expression.the apply icon.Since constructors are functions, the match icon has a topology similar tox3JustJustx3JustJust(Just x) = Just 3Continuing on, here is a simple pattern match.y218baz27++*44*2+-/y218baz27++*44*2+-/y = (((2 + 4 * 4) - (7+ 2 + baz)*8)/21)Other tree layouts could make these large expressions much more readable.(just like long lines of code) become hard to read with the linear layout.The linear layout Glance currently uses is just the simplest. Large expressionsThere are many different ways that function application trees can be represented.y8*3+foo2bazy8*3+foo2bazy = foo (3 + bazOf2) (8* bazOf2) where bazOf2 = baz 2and Glance extracts the sub-expression into a separate (non-nested) icon.As soon as an expression is used more than once, the tree topology is lost,y2baz8*2baz3+fooy2baz8*2baz3+fooy = foo (3 + (baz 2)) (8 * (baz 2))to make its drawings more compact.sub-expression is only used once. Glance takes advantage of this tree topologyapplication has a tree topology, not a graph topology. The result of eachand no it does not look graphical. The core idea is that nested functiondoes not look very graphical. Here graphical is referring to a graph topology,programming languages, you may be thinking that drawing belowLet's go back to the function apply icon. If you are used to other graphicalf1+f1+f1 x y = (\z -> x + z) yafter layout so it would not make the drawing any larger.to have Glance draw a perimeter around all icons inside a function. This would occurfigure out that x is only being used in an inner function. To address this, I hopeis used. In the code below for example, it would probably take some time toWithout regions however, it can be difficult to see in which function a parameterregions.In most other visual languages, the above code would require three nestedf1[,,]sumx3x2x1f1[,,]sumx3x2x1f1 = (\x1 -> (\x2 -> (\x3 -> sum [x1, x2, x3])))is not wasted by extra boxes.Theoretically, Glance's flat layout should allow more compact drawings since spacewould be restricted to a rectangle. In Glance, all icons are on the same level.In other visual programming languages, the icons inside the body of a functionSomething different about Glance is that Glance does not have any rigid code regions.f1+2*maxf1+2*maxf x y = max (2 * y) (1 + x)---------Drawing below:-----------------------------Scroll down for the drawing.Haskell functions only have one parameter).with "multiple parameters" are defined (which is of course syntactic sugar sinceyourself before scrolling down. One place to start is to figure out how functionsIf you have some drawing implements handy, you might want to try drawing thisf x y = max (2 * y) (1 + x)A more complex example:y73*y73*y = (\x -> 3 * x) 7function application is bound to y.Here, the new function is applied to the argument 7, and the result of thef3*f3*f = (\x -> 3 * x)which is connected to the blue square. The function itself is bound to the name f.and the return value 3 * x is the red circle in the function application icon,In this case, the formal parameter x is the dot inside the green lambda icon,that has been defined.of the -> in a lambda expression). The green circle represents the functionrepresents the value returned by function (i.e. what's on the right sizefunction. The dot inside the icon is the formal parameter. The blue squareNow for the answer. As you might have suspected. The green icon defines ay73*y73*y has a value of 21.and a result that derives from the variable? Here's a hint.What construct in Haskell has three ingredients: a name, a variable,overall result f, the second argument to *, and the result of the multiplication.in the green icon. So the green icon represents a relationship between theThe result of the function application is also connected to the blue squareso the second argument probably comes from the dot in the green icon.There is a line connecting the second argument of * to the dot in the green icon,function application. It looks like 3 is being multiplied by something, but what?box which indicates that it is bound to the result. Now look at theLet's try to figure it out. First look at the f. It's green and in an orangef3*f3*That was probably not too surprising. How about this?y278+*y278+*y = (*) ((+) 8 7) 2Let's make things a bit more interesting with a nested function application.it means they have the same value. Line colors are randomized.etc.) in textual Haskell. Thus if two things are connected with a line in Glance,Lines in Glance are largely equivalent to names (variable names, function names,The meaning of Glance is entirely in how the icons are connected to each other.even if they are rotated, reflected, squashed or squished does not matter.icons (the non-text parts) are distinguishable from each other, how they are drawn,of the icons does not have much meaning. In fact, as long as theit will start looking much stranger from here on. Keep in mind that the designthe program text with some boxes, lines, triangles and circles. Don't worry,You might be thinking that so far it looks like Glance has just decoratedy53*y53*y = 3 * 5Infix function application is displayed the same.y53*y53*y = (*) 3 5For example, multiply 3 and 5 and bind the result to y.resultargumentfunctionresultargumentfunctionMore explicitlyyxfyxfThe function f is applied to the argument x, and the result is bound to y.Let's start with y = f x.programming language designs waiting to be discovered.visual programming languages, and that there is a huge universe of visualHow could it be extended? I feel that we are just at the very beginning ofWhy is Glance designed the way it is? What are other ways it could work?Glance drawings, but also to get you thinking about visual programming languages.Welcome to Glance! My goal for this tutorial is teach you how to read \ No newline at end of file + "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">factorial*-110==factorial*-110== else x * factorial (x - 1) then 1 if x == 0factorial x =Notice that the nesting depth has been reduced from 3 to 2.(x *) . factorial . (x -) $ 1Glance essentially rewrites the second expression as:x * factorial (x - 1)tofactorial (x - 1) * xTo enable the compose icon, we change the expressionuses a compose icon for the else expression.For example, if we slightly rewrite the factorial function above, Glancereduce the nesting depth.Glance figures out automatically when to use the compose icon in order toyfghxyfghxy = (f . g . h) xwhich is the same asy = f (g (h x))With a composition of three functions:yfgxyfgxy = (f . g) xwhich is the same asy = f (g x)For example:to a composition of functions.To reduce nesting depth, Glance has an icon that represents an argument appliedinside an apply icon (depth=3).depth of 3, since it is an apply icon (depth=1), inside an apply icon (depth=2),For example, The icon representing "factorial (x - 1) * x" above has a nestingThe depth of an icon's application tree is called the nesting depth.Compose (bonus section):factorial1-*10==factorial1-*10== else factorial (x - 1) * x then 1 if x == 0factorial x ="If" expressions are rendered the same as a guard with only one Boolean.topology, but they should look less similar in better icon versions.Currently, the guard icon and the case icon look similar since they have similarto the bottom of the mid-line.other side of the mid-line. The overall result that the guard is bound to connectscorresponding result expressions (e.g. x + 1) connect to the triangles on theThe Boolean expressions (e.g. x == 0) connect to the orange Ls, and they1x+otherwise10x==y1x+otherwise10x== | otherwise = x + 1y | x == 0 = 1Guards and if expressions look like this:Guards:the result of (x + 1) to a new yellow circle.(x + 1) is connected to its pattern (Just x), Glance can connectuse any value from the pattern (Nothing). For the second match, since the resultconnects to the circle on the case icon since the right hand side (0) does notThe result for the first match (Nothing -> 0)with the yellow circle.The patterns connect to the triangles, and the result for each match is indicatedThe case icon is the magenta icon with three yellow circles next to it.y1+JustNothing0maybeInty1+JustNothing0maybeInt Just x -> x + 1 Nothing -> 0y = case maybeInt ofNow that you are familiar with matches, here's a simple case expression.the apply icon.Since data constructors are functions, the match icon has a topology similar tox3JustJustx3JustJust(Just x) = Just 3Continuing on, here is a simple pattern match.Patterns:y218baz27++*44*2+-/y218baz27++*44*2+-/y = (((2 + 4 * 4) - (7+ 2 + baz)*8)/21)Other tree layouts could make these large expressions much more readable.(just like long lines of code) become hard to read with the linear layout.The linear layout Glance currently uses is just the simplest. Large expressionsThere are many different ways that function application trees can be represented.y8*3+foo2bazy8*3+foo2bazy = foo (3 + bazOf2) (8* bazOf2) where bazOf2 = baz 2and Glance extracts the sub-expression into a separate (non-nested) icon.As soon as an expression is used more than once, the tree topology is lost,y2baz8*2baz3+fooy2baz8*2baz3+fooy = foo (3 + (baz 2)) (8 * (baz 2))to make its drawings more compact.sub-expression is only used once. Glance takes advantage of this tree topologyapplication has a tree topology, not a graph topology. The result of eachand no it does not look graphical. The core idea is that nested functiondoes not look very graphical. Here graphical is referring to a graph topology,programming languages, you may be thinking that the drawing belowLet's go back to the function apply icon. If you are used to other graphicalGraph and Tree Topology:f1+f1+f1 x y = (\z -> x + z) yafter layout so it would not make the drawing any larger.to have Glance draw a perimeter around all icons inside a function. This would occurfigure out that x is only being used in an inner function. To address this, I hopeis used. In the code below for example, it would probably take some time toWithout regions however, it can be difficult to see in which function a parameterregions.In most other visual languages, the above code would require three nestedf1[,,]sumx3x2x1f1[,,]sumx3x2x1f1 = (\x1 -> (\x2 -> (\x3 -> sum [x1, x2, x3])))is not wasted by extra boxes.Theoretically, Glance's flat layout should allow more compact drawings since spacewould be restricted to a rectangle. In Glance, all icons are on the same level.In other visual programming languages, the icons inside the body of a functionSomething different about Glance is that Glance does not have any rigid code regions.No Code Regions:f1+2*maxf1+2*maxf x y = max (2 * y) (1 + x)---------Drawing below:-----------------------------Scroll down for the drawing.Haskell functions only have one parameter).with "multiple parameters" are defined (which is of course syntactic sugar sinceyourself before scrolling down. One place to start is to figure out how functionsIf you have some drawing implements handy, you might want to try drawing thisf x y = max (2 * y) (1 + x)A more complex example:y73*y73*y = (\x -> 3 * x) 7function application is bound to y.Here, the new function is applied to the argument 7, and the result of thef3*f3*f = (\x -> 3 * x)which is connected to the blue square. The function itself is bound to the name f.and the return value 3 * x is the red circle in the function application icon,In this case, the formal parameter x is the dot inside the green lambda icon,that has been defined.of the -> in a lambda expression). The green circle represents the functionrepresents the value returned by function (i.e. what's on the right sidefunction. The dot inside the icon is the formal parameter. The blue squareNow for the answer. As you might have suspected. The green icon defines ay73*y73*y has a value of 21.and a result that derives from the variable? Here's a hint.What construct in Haskell has three ingredients: a name, a variable,overall result f, the second argument to *, and the result of the multiplication.in the green icon. So the green icon represents a relationship between theThe result of the function application is also connected to the blue squareso the second argument probably comes from the dot in the green icon.There is a line connecting the second argument of * to the dot in the green icon,function application. It looks like 3 is being multiplied by something, but what?box which indicates that it is bound to the result. Now look at theLet's try to figure it out. First look at the f. It's green and in an orangef3*f3*represent?That was probably not too surprising. How about this? What does the green iconThe Mystery Icon:y278+*y278+*y = (*) ((+) 8 7) 2Let's make things a bit more interesting with a nested function application.it means they have the same value. Line colors are randomized.etc.) in textual Haskell. Thus if two things are connected with a line in Glance,Lines in Glance are largely equivalent to names (variable names, function names,The meaning of Glance is entirely in how the icons are connected to each other.even if they are rotated, reflected, squashed or squished does not matter.icons (the non-text parts) are distinguishable from each other, how they are drawn,of the icons does not have much meaning. In fact, as long as theit will start looking much stranger from here on. Keep in mind that the designthe program text with some boxes, lines, triangles and circles. Don't worry,You might be thinking that so far it looks like Glance has just decoratedy53*y53*y = 3 * 5Infix function application is displayed the same.y53*y53*y = (*) 3 5For example, multiply 3 and 5 and bind the result to y.resultargumentfunctionresultargumentfunctionMore explicitlyyxfyxfThe function f is applied to the argument x, and the result is bound to y.Let's start with y = f x.Function Application:of Haskell.This tutorial assumes that the reader has some familiarity with the basicsprogramming language designs waiting to be discovered.visual programming languages, and that there is a huge universe of visualHow could it be extended? I feel that we are just at the very beginning ofWhy is Glance designed the way it is? What are other ways it could work?Glance drawings, but also to get you thinking about visual programming languages.Welcome to Glance! My goal for this tutorial is teach you how to read \ No newline at end of file