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