changeset 249 | 5c211dd7e5ad |
parent 248 | 11851b20fb78 |
child 250 | ab9e09076462 |
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 |