ProgTutorial/FirstSteps.thy
changeset 249 5c211dd7e5ad
parent 248 11851b20fb78
child 250 ab9e09076462
equal deleted inserted replaced
248:11851b20fb78 249:5c211dd7e5ad
  1695 
  1695 
  1696 section {* Pretty-Printing\label{sec:pretty} *}
  1696 section {* Pretty-Printing\label{sec:pretty} *}
  1697 
  1697 
  1698 text {*
  1698 text {*
  1699   So far we printed out only plain strings without any formatting except for
  1699   So far we printed out only plain strings without any formatting except for
  1700   occasional explicit line breaks using @{text [quotes] "\\n"}. This is
  1700   occasional explicit linebreaks using @{text [quotes] "\\n"}. This is
  1701   sufficient for ``quick-and-dirty'' printouts. For something more
  1701   sufficient for ``quick-and-dirty'' printouts. For something more
  1702   sophisticated, Isabelle includes an infrastructure for formatting text.
  1702   sophisticated, Isabelle includes an infrastructure for properly formatting text.
  1703   This infrastructure is quite useful for printing for example large formulae.  
  1703   This infrastructure is loosely based on a paper by Oppen~\cite{Oppen80}. Most of
  1704   It is loosely based on a paper by Oppen~\cite{Oppen80}. Most of
       
  1705   its functions do not operate on @{ML_type string}s, but on instances of the
  1704   its functions do not operate on @{ML_type string}s, but on instances of the
  1706   type:
  1705   type:
  1707 
  1706 
  1708   @{ML_type [display, gray] "Pretty.T"}
  1707   @{ML_type [display, gray] "Pretty.T"}
  1709 
  1708 
  1712 
  1711 
  1713   @{ML_response_fake [display,gray]
  1712   @{ML_response_fake [display,gray]
  1714   "Pretty.str \"test\"" "String (\"test\", 4)"}
  1713   "Pretty.str \"test\"" "String (\"test\", 4)"}
  1715 
  1714 
  1716   where the result indicates that we transformed a string with length 4. Once
  1715   where the result indicates that we transformed a string with length 4. Once
  1717   you have a pretty type, you can, for example, control where line breaks can
  1716   you have a pretty type, you can, for example, control where linebreaks may
  1718   occur in case the text wraps over a line, or with how much indentation a
  1717   occur in case the text wraps over a line, or with how much indentation a
  1719   text should be printed.  However, if you want to actually output the
  1718   text should be printed.  However, if you want to actually output the
  1720   formatted text, you have to transform the pretty type back into a @{ML_type
  1719   formatted text, you have to transform the pretty type back into a @{ML_type
  1721   string}. This can be done with the function @{ML Pretty.string_of}. In what
  1720   string}. This can be done with the function @{ML Pretty.string_of}. In what
  1722   follows we will use the following wrapper function for printing a pretty
  1721   follows we will use the following wrapper function for printing a pretty
  1724 *}
  1723 *}
  1725 
  1724 
  1726 ML{*fun pprint prt = writeln (Pretty.string_of prt)*}
  1725 ML{*fun pprint prt = writeln (Pretty.string_of prt)*}
  1727 
  1726 
  1728 text {*
  1727 text {*
  1729   The point of the pretty-printing infrastructure is to give hints how to
  1728   The point of the pretty-printing infrastructure is to give hints about how to
  1730   layout text and let the system do the actual layout. Let us first explain
  1729   layout text and let Isabelle do the actual layout. Let us first explain
  1731   how you can insert places where a line break can occur. For this assume the
  1730   how you can insert places where a linebreak can occur. For this assume the
  1732   following function that replicates a string n times:
  1731   following function that replicates a string n times:
  1733 *}
  1732 *}
  1734 
  1733 
  1735 ML{*fun rep n str = implode (replicate n str) *}
  1734 ML{*fun rep n str = implode (replicate n str) *}
  1736 
  1735 
  1739 *}
  1738 *}
  1740 
  1739 
  1741 ML{*val test_str = rep 8 "fooooooooooooooobaaaaaaaaaaaar "*}
  1740 ML{*val test_str = rep 8 "fooooooooooooooobaaaaaaaaaaaar "*}
  1742 
  1741 
  1743 text {*
  1742 text {*
  1744   Since @{ML test_str} is a string spanning over more than one line, we 
  1743   We deliberately chosed a large string so that is spans over more than one line. 
  1745   obtain the ugly
  1744   If we print out the string using the usual ``quick-and-dirty'' method, then
       
  1745   we obtain the ugly output:
  1746 
  1746 
  1747 @{ML_response_fake [display,gray]
  1747 @{ML_response_fake [display,gray]
  1748 "writeln test_str"
  1748 "writeln test_str"
  1749 "fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar foooooooooo
  1749 "fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar foooooooooo
  1750 ooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaa
  1750 ooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaa
  1751 aaaaaaar fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar fo
  1751 aaaaaaar fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar fo
  1752 oooooooooooooobaaaaaaaaaaaar"}
  1752 oooooooooooooobaaaaaaaaaaaar"}
  1753 
  1753 
  1754   if we print the string by the usual ``quick-and-dirty'' method. 
       
  1755   We obtain the same if we just use
  1754   We obtain the same if we just use
  1756 
  1755 
  1757 @{ML_response_fake [display,gray]
  1756 @{ML_response_fake [display,gray]
  1758 "pprint (Pretty.str test_str)"
  1757 "pprint (Pretty.str test_str)"
  1759 "fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar foooooooooo
  1758 "fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar foooooooooo
  1760 ooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaa
  1759 ooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaa
  1761 aaaaaaar fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar fo
  1760 aaaaaaar fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar fo
  1762 oooooooooooooobaaaaaaaaaaaar"}
  1761 oooooooooooooobaaaaaaaaaaaar"}
  1763 
  1762 
  1764   However by using pretty types you have the ability to indicate a possible
  1763   However by using pretty types you have the ability to indicate a possible
  1765   line break for example at each space. You can achieve this with the function
  1764   linebreak for example at each space. You can achieve this with the function
  1766   @{ML Pretty.breaks}, which expects a list of pretty types and inserts a
  1765   @{ML Pretty.breaks}, which expects a list of pretty types and inserts a
  1767   possible line break in between every two elements in this list. To print
  1766   possible linebreak in between every two elements in this list. To print
  1768   this this list of pretty types as a single string, we concatenate them 
  1767   this list of pretty types as a single string, we concatenate them 
  1769   with the function @{ML Pretty.blk} as follows
  1768   with the function @{ML Pretty.blk} as follows:
  1770 
  1769 
  1771 
  1770 
  1772 @{ML_response_fake [display,gray]
  1771 @{ML_response_fake [display,gray]
  1773 "let
  1772 "let
  1774   val ptrs = map Pretty.str (space_explode \" \" test_str)
  1773   val ptrs = map Pretty.str (space_explode \" \" test_str)
  1779 fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar 
  1778 fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar 
  1780 fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar
  1779 fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar
  1781 fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar"}
  1780 fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar"}
  1782 
  1781 
  1783   Here the layout of @{ML test_str} is much more pleasing to the 
  1782   Here the layout of @{ML test_str} is much more pleasing to the 
  1784   eye. The @{ML "0"} in @{ML Pretty.blk} stands for a zero-indentation
  1783   eye. The @{ML "0"} in @{ML Pretty.blk} stands for no indentation
  1785   of the printed string. If you increase the indentation, you obtain
  1784   of the printed string. You can increase the indentation and obtain
  1786   
  1785   
  1787 @{ML_response_fake [display,gray]
  1786 @{ML_response_fake [display,gray]
  1788 "let
  1787 "let
  1789   val ptrs = map Pretty.str (space_explode \" \" test_str)
  1788   val ptrs = map Pretty.str (space_explode \" \" test_str)
  1790 in
  1789 in
  1809           fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar 
  1808           fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar 
  1810           fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar
  1809           fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar
  1811           fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar"}
  1810           fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar"}
  1812 
  1811 
  1813   If you want to print out a list of items separated by commas and 
  1812   If you want to print out a list of items separated by commas and 
  1814   have the line breaks handled properly, you can use the function 
  1813   have the linebreaks handled properly, you can use the function 
  1815   @{ML Pretty.commas}. For example
  1814   @{ML Pretty.commas}. For example
  1816 
  1815 
  1817 @{ML_response_fake [display,gray]
  1816 @{ML_response_fake [display,gray]
  1818 "let
  1817 "let
  1819   val ptrs = map (Pretty.str o string_of_int) (99998 upto 100020)
  1818   val ptrs = map (Pretty.str o string_of_int) (99998 upto 100020)
  1823 "99998, 99999, 100000, 100001, 100002, 100003, 100004, 100005, 100006, 
  1822 "99998, 99999, 100000, 100001, 100002, 100003, 100004, 100005, 100006, 
  1824 100007, 100008, 100009, 100010, 100011, 100012, 100013, 100014, 100015, 
  1823 100007, 100008, 100009, 100010, 100011, 100012, 100013, 100014, 100015, 
  1825 100016, 100017, 100018, 100019, 100020"}
  1824 100016, 100017, 100018, 100019, 100020"}
  1826 
  1825 
  1827   where @{ML upto} generates a list of integers. You can print this
  1826   where @{ML upto} generates a list of integers. You can print this
  1828   list out as an ``set'' enclosed inside @{text [quotes] "{"} and
  1827   list out as an ``set'', that means enclosed inside @{text [quotes] "{"} and
  1829   @{text [quotes] "}"}, and separated by commas by using the function
  1828   @{text [quotes] "}"}, and separated by commas using the function
  1830   @{ML Pretty.enum}. For example
  1829   @{ML Pretty.enum}. For example
  1831 *}
  1830 *}
  1832 
  1831 
  1833 text {*
  1832 text {*
  1834   
  1833   
  1844 
  1843 
  1845   As can be seen, this function prints out the ``set'' so that starting 
  1844   As can be seen, this function prints out the ``set'' so that starting 
  1846   from the second each new line as an indentation of 2.
  1845   from the second each new line as an indentation of 2.
  1847   
  1846   
  1848   If you print something out which goes beyond the capabilities of the
  1847   If you print something out which goes beyond the capabilities of the
  1849   standard function, you can do the formating yourself. Assume you want
  1848   standard function, you can do realatively easily the formating
  1850   to print out a list of items where like in English the last two items
  1849   yourself. Assume you want to print out a list of items where like in ``English''
  1851   are separated by @{text [quotes] "and"}. For this you can write the 
  1850   the last two items are separated by @{text [quotes] "and"}. For this you can
  1852   function
  1851   write the function
       
  1852 
  1853 *}
  1853 *}
  1854 
  1854 
  1855 ML %linenosgray{*fun and_list [] = []
  1855 ML %linenosgray{*fun and_list [] = []
  1856   | and_list [x] = [x]
  1856   | and_list [x] = [x]
  1857   | and_list xs = 
  1857   | and_list xs = 
  1863       end *}
  1863       end *}
  1864 
  1864 
  1865 text {*
  1865 text {*
  1866   where in Line 7 we print the beginning of the list and in Line
  1866   where in Line 7 we print the beginning of the list and in Line
  1867   8 the last item. We have to use @{ML "Pretty.brk 1"} in order
  1867   8 the last item. We have to use @{ML "Pretty.brk 1"} in order
  1868   to insert a space (of length 1) before the @{text [quotes] "and"}
  1868   to insert a space (of length 1) before the 
  1869   where we also want that a line break can occur. We do the
  1869   @{text [quotes] "and"}. This space is also a pleace where a linebreak 
  1870   same ater the @{text [quotes] "and"}. This gives you
  1870   can occur. We do the same ater the @{text [quotes] "and"}. This gives you
       
  1871   for example
  1871 
  1872 
  1872 @{ML_response_fake [display,gray]
  1873 @{ML_response_fake [display,gray]
  1873 "let
  1874 "let
  1874   val ptrs = map (Pretty.str o string_of_int) (1 upto 22)
  1875   val ptrs = map (Pretty.str o string_of_int) (1 upto 22)
  1875 in
  1876 in
  1876   pprint (Pretty.blk (0, and_list ptrs))
  1877   pprint (Pretty.blk (0, and_list ptrs))
  1877 end"
  1878 end"
  1878 "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 
  1879 "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 
  1879 and 22"}
  1880 and 22"}
  1880 
  1881 
  1881   Next we like to pretty print a term and its type. For this we use the
  1882   Next we like to pretty-print a term and its type. For this we use the
  1882   function @{text "tell_type"}:
  1883   function @{text "tell_type"}.
  1883 *}
  1884 *}
  1884 
  1885 
  1885 ML %linenosgray{*fun tell_type ctxt t = 
  1886 ML %linenosgray{*fun tell_type ctxt t = 
  1886 let
  1887 let
  1887   fun pstr s = Pretty.breaks (map Pretty.str (space_explode " " s))
  1888   fun pstr s = Pretty.breaks (map Pretty.str (space_explode " " s))
  1892     (pstr "The term " @ [ptrm] @ pstr " has type " 
  1893     (pstr "The term " @ [ptrm] @ pstr " has type " 
  1893       @ [pty, Pretty.str "."])))
  1894       @ [pty, Pretty.str "."])))
  1894 end*}
  1895 end*}
  1895 
  1896 
  1896 text {*
  1897 text {*
  1897   In Line 3 we define a function that inserts possible linebreaks into 
  1898   In Line 3 we define a function that inserts according to spaces 
  1898   an (English) text according to spaces. In Lines 4 and 5 we pretty print
  1899   possible linebreaks into an (English). In Lines 4 and 5 we pretty-print
  1899   the term and its type using the functions @{ML Syntax.pretty_term} and
  1900   the term and its type using the functions @{ML Syntax.pretty_term} and
  1900   @{ML Syntax.pretty_typ}. We also use the function @{ML Pretty.quote}
  1901   @{ML Syntax.pretty_typ}. We also use the function @{ML Pretty.quote}
  1901   in order to enclose the term and type with quotes. In Line 9 we add the 
  1902   in order to enclose the term and type inside quotation marks. In Line 
  1902   period right after the type without the possibility of a line break, 
  1903   9 we add a period right after the type without the possibility of a 
  1903   because we do not want that a line break occurs there.
  1904   linebreak, because we do not want that a linebreak occurs there.
  1904 
  1905 
  1905   Now you can write
  1906   Now you can write
  1906 
  1907 
  1907   @{ML_response_fake [display,gray]
  1908   @{ML_response_fake [display,gray]
  1908   "tell_type @{context} @{term \"min (Suc 0)\"}"
  1909   "tell_type @{context} @{term \"min (Suc 0)\"}"
  1909   "The term \"min (Suc 0)\" has type \"nat \<Rightarrow> nat\"."}
  1910   "The term \"min (Suc 0)\" has type \"nat \<Rightarrow> nat\"."}
  1910   
  1911   
  1911   You can see the proper line breaking with the term
  1912   To see the proper linebreaking, you can try out the function on a bigger term 
       
  1913   and type.
  1912 
  1914 
  1913   @{ML_response_fake [display,gray]
  1915   @{ML_response_fake [display,gray]
  1914   "tell_type @{context} @{term \"op = (op = (op = (op = (op = op =))))\"}"
  1916   "tell_type @{context} @{term \"op = (op = (op = (op = (op = op =))))\"}"
  1915   "The term \"op = (op = (op = (op = (op = op =))))\" has type 
  1917   "The term \"op = (op = (op = (op = (op = op =))))\" has type 
  1916 \"((((('a \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool\"."}
  1918 \"((((('a \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool\"."}
  1929   colours
  1931   colours
  1930 
  1932 
  1931   What happens with big formulae?
  1933   What happens with big formulae?
  1932 
  1934 
  1933   \begin{readmore}
  1935   \begin{readmore}
  1934   The general infrastructure for pretty printing is implemented in 
  1936   The general infrastructure for pretty-printing is implemented in the file
  1935   @{ML_file "Pure/General/pretty.ML"}. The file @{ML_file "Pure/Syntax/syntax.ML"}
  1937   @{ML_file "Pure/General/pretty.ML"}. The file @{ML_file "Pure/Syntax/syntax.ML"}
  1936   contains pretty printing functions for terms, types, theorems and so on.
  1938   contains pretty-printing functions for terms, types, theorems and so on.
  1937   \end{readmore}
  1939   \end{readmore}
  1938 *}
  1940 *}
  1939 
  1941 
  1940 section {* Misc (TBD) *}
  1942 section {* Misc (TBD) *}
  1941 
  1943