https://wiki.haskell.org/api.php?action=feedcontributions&user=BrettGiles&feedformat=atomHaskellWiki - User contributions [en]2021-09-21T19:53:56ZUser contributionsMediaWiki 1.27.4https://wiki.haskell.org/index.php?title=Gtk2Hs&diff=26984Gtk2Hs2009-03-15T14:34:04Z<p>BrettGiles: /* Article as of Mid 2008 */ Sigh - Typo of my typo</p>
<hr />
<div>[[Category:User interfaces]]<br />
== What is it? ==<br />
<br />
Gtk2Hs is a Haskell binding to Gtk+ 2.x.<br />
Using it, one can write Gtk+ based applications with GHC.<br />
<br />
== Homepage ==<br />
<br />
http://haskell.org/gtk2hs/<br />
<br />
== Status ==<br />
<br />
It currently works with Gtk+ 2.0 through to 2.8 on Unix, Win32 and MacOS X.<br />
The widget function coverage is almost complete, only a few minor bits and pieces are missing.<br />
<br />
It currently builds with ghc 5.04.3 through to 6.8.2<br />
<br />
== Installation Notes ==<br />
=== Mac OS X ===<br />
<br />
==== Using the GTK+ OS X Framework ====<br />
<br />
This explains how to install Gtk2Hs on Macs using the native [http://www.gtk-osx.org/ GTK+ OS X Framework], a port of GTK+ to the Mac that does '''not''' depend on X11, and hence, is better integrated into the Mac desktop - i.e., menus actually appear in the menu bar, where they belong. It also avoids the often tedious installation of GTK+ via MacPorts. However, it misses support for optional Gtk2Hs packages that are currently not supported by the [http://www.gtk-osx.org/ GTK+ OS X Framework], most notably support for Glade. It does include support for Cairo, though.<br />
<br />
Here is how to install the library:<br />
# Download and install [http://www.gtk-osx.org/ GTK+ OS X Framework] (this uses the standard Mac package installer).<br />
# Install [http://pkg-config.freedesktop.org/ pkg-config], either by compiling it from source or via MacPorts.<br />
# Download and unpack the Gtk2Hs tar ball from the [http://www.haskell.org/gtk2hs/downloads/ Gtk2Hs download page] (I tested 0.10.0).<br />
# Configure with (you may want to remove the two backslashes and put everything on one line)<br />
env PKG_CONFIG_PATH=/Library/Frameworks/Cairo.framework/Resources/dev/lib/pkgconfig:\ <br />
/Library/Frameworks/GLib.framework/Resources/dev/lib/pkgconfig:\ <br />
/Library/Frameworks/Gtk.framework/Resources/dev/lib/pkgconfig ./configure --disable-gio<br />
# Build with<br />
make<br />
# Install (to <tt>/usr/local/</tt> unless a <tt>--prefix</tt> option was passed to <tt>configure</tt>) with<br />
sudo make install<br />
<br />
The library is now registered with the package database of the GHC you used for compiling.<br />
<br />
NB: Thanks to Ross Mellgren for his post on the gtk2hs-users list that outlined the use of <tt>PKG_CONFIG_PATH</tt>.<br />
<br />
==== Article as of Mid 2008 ====<br />
Installing Gtk2Hs on Mac requires some finesse, at least until Haskell Libary Platform is built or ghc-6.8.3 is <br />
available in macports. (These are planned for late 2008.)<br />
<br />
* Install [http://macports.org MacPorts]<br />
* Install dependencies:<br />
sudo port install glade3 libglade2 gstreamer gst-plugins-base gtksourceview cairo librsvg gtkglext firefox<br />
* Update PKG_CONFIG_PATH (for libraries)<br />
export PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig:/opt/local/lib/pkgconfig<br />
* Update ghc to use macports libs: Edit your main <tt>ghc</tt> driver program and change the last line to:<br />
exec $GHCBIN $TOPDIROPT ${1+"$@"} -L/opt/local/lib -I/opt/local/include<br />
* Download Gtk2Hs following instructions at [http://www.haskell.org/gtk2hs/downloads/ Gtk2Hs Download page]<br />
* Check configuration:<br />
./configure --enable-docs --enable-profiling<br />
<br />
...<br />
<br />
**************************************************<br />
* Configuration completed successfully. <br />
* <br />
* The following packages will be built: <br />
* <br />
* glib : yes <br />
* gtk : yes <br />
* glade : yes <br />
* cairo : yes <br />
* svgcairo : yes <br />
* gtkglext : yes <br />
* gconf : yes <br />
* sourceview : yes <br />
* mozembed : yes <br />
* soegtk : yes <br />
* gnomevfs : yes <br />
* gstreamer : yes <br />
* documentation : yes <br />
* <br />
* Now do "(g)make" followed by "(g)make install"<br />
**************************************************<br />
* Build and Install:<br />
make <br />
sudo make install<br />
<br />
==== Recent experiences ====<br />
I successfully installed the latest version on Mac OS 10.5 by:<br />
* Installing Macports.<br />
* <tt>sudo port install ghc</tt><br />
* <tt>sudo port install gtk2hs</tt> - which does not complete successfully. It does however, install the appropriate dependencies. Note that there are so many, you may need to install a couple of times due to time outs etc.. The build of Gtk2HS will fail, but that is ok - continue as below.<br />
* Remove the build directory under <tt>/opt/.../build/gtk2hs</tt><br />
* Download Gtk2Hs via darcs as per [http://haskell.org/gtk2hs/development/#darcs the gtk2hs download instructions]<br />
* do a <tt>sudo port install automake</tt><br />
* do a <tt>sudo port install alex</tt><br />
* do a <tt>sudo port install happy</tt> (Note this also fails and must be built from source. See the [[Happy]] page for details.)<br />
* Follow the build instructions on the [http://haskell.org/gtk2hs/development/#darcs the gtk2hs download page]. I would suggest using <tt>./configure --prefix=/opt/local</tt> to get it in the same place as ports - personal preference though.<br />
Good luck - as usual, your mileage may vary.<br />
<br />
== Demos ==<br />
<br />
=== OpenGL and Gtk2Hs ===<br />
<br />
[[Gtk2Hs/Demos/GtkGLext/hello.hs]]<br />
<br />
[[Gtk2Hs/Demos/GtkGLext/terrain.hs]] requires [[Gtk2Hs/Demos/GtkGLext/terrain.xpm]]<br />
<br />
==FAQs==<br />
These are links to FAQS on the main site.<br />
*[http://haskell.org/gtk2hs/archives/2005/06/23/hiding-the-console-on-windows/#more-26 Hiding the console on windows]<br />
*[http://haskell.org/gtk2hs/archives/2005/07/24/writing-multi-threaded-guis/#more-38 Writing multi-threaded GUIs]<br />
*[http://haskell.org/gtk2hs/archives/2005/06/24/building-from-source-on-windows/#more-15 Building on Windows]<br />
*[http://haskell.org/gtk2hs/development/#darcs Checkout instructions]. Also see [[Darcs]]<br />
<br />
[[Category:Applications]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=Gtk2Hs&diff=26983Gtk2Hs2009-03-15T14:33:38Z<p>BrettGiles: /* Article as of Mid 2008 */ typo correction</p>
<hr />
<div>[[Category:User interfaces]]<br />
== What is it? ==<br />
<br />
Gtk2Hs is a Haskell binding to Gtk+ 2.x.<br />
Using it, one can write Gtk+ based applications with GHC.<br />
<br />
== Homepage ==<br />
<br />
http://haskell.org/gtk2hs/<br />
<br />
== Status ==<br />
<br />
It currently works with Gtk+ 2.0 through to 2.8 on Unix, Win32 and MacOS X.<br />
The widget function coverage is almost complete, only a few minor bits and pieces are missing.<br />
<br />
It currently builds with ghc 5.04.3 through to 6.8.2<br />
<br />
== Installation Notes ==<br />
=== Mac OS X ===<br />
<br />
==== Using the GTK+ OS X Framework ====<br />
<br />
This explains how to install Gtk2Hs on Macs using the native [http://www.gtk-osx.org/ GTK+ OS X Framework], a port of GTK+ to the Mac that does '''not''' depend on X11, and hence, is better integrated into the Mac desktop - i.e., menus actually appear in the menu bar, where they belong. It also avoids the often tedious installation of GTK+ via MacPorts. However, it misses support for optional Gtk2Hs packages that are currently not supported by the [http://www.gtk-osx.org/ GTK+ OS X Framework], most notably support for Glade. It does include support for Cairo, though.<br />
<br />
Here is how to install the library:<br />
# Download and install [http://www.gtk-osx.org/ GTK+ OS X Framework] (this uses the standard Mac package installer).<br />
# Install [http://pkg-config.freedesktop.org/ pkg-config], either by compiling it from source or via MacPorts.<br />
# Download and unpack the Gtk2Hs tar ball from the [http://www.haskell.org/gtk2hs/downloads/ Gtk2Hs download page] (I tested 0.10.0).<br />
# Configure with (you may want to remove the two backslashes and put everything on one line)<br />
env PKG_CONFIG_PATH=/Library/Frameworks/Cairo.framework/Resources/dev/lib/pkgconfig:\ <br />
/Library/Frameworks/GLib.framework/Resources/dev/lib/pkgconfig:\ <br />
/Library/Frameworks/Gtk.framework/Resources/dev/lib/pkgconfig ./configure --disable-gio<br />
# Build with<br />
make<br />
# Install (to <tt>/usr/local/</tt> unless a <tt>--prefix</tt> option was passed to <tt>configure</tt>) with<br />
sudo make install<br />
<br />
The library is now registered with the package database of the GHC you used for compiling.<br />
<br />
NB: Thanks to Ross Mellgren for his post on the gtk2hs-users list that outlined the use of <tt>PKG_CONFIG_PATH</tt>.<br />
<br />
==== Article as of Mid 2008 ====<br />
Installing Gtk2Hs on Mac requires some finesse, at least until Haskell Libary Platform is built or ghc-6.8.3 is <br />
available in macports. (These are planned for late 2008.)<br />
<br />
* Install [http://macports.org MacPorts]<br />
* Install dependencies:<br />
sudo port insatll glade3 libglade2 gstreamer gst-plugins-base gtksourceview cairo librsvg gtkglext firefox<br />
* Update PKG_CONFIG_PATH (for libraries)<br />
export PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig:/opt/local/lib/pkgconfig<br />
* Update ghc to use macports libs: Edit your main <tt>ghc</tt> driver program and change the last line to:<br />
exec $GHCBIN $TOPDIROPT ${1+"$@"} -L/opt/local/lib -I/opt/local/include<br />
* Download Gtk2Hs following instructions at [http://www.haskell.org/gtk2hs/downloads/ Gtk2Hs Download page]<br />
* Check configuration:<br />
./configure --enable-docs --enable-profiling<br />
<br />
...<br />
<br />
**************************************************<br />
* Configuration completed successfully. <br />
* <br />
* The following packages will be built: <br />
* <br />
* glib : yes <br />
* gtk : yes <br />
* glade : yes <br />
* cairo : yes <br />
* svgcairo : yes <br />
* gtkglext : yes <br />
* gconf : yes <br />
* sourceview : yes <br />
* mozembed : yes <br />
* soegtk : yes <br />
* gnomevfs : yes <br />
* gstreamer : yes <br />
* documentation : yes <br />
* <br />
* Now do "(g)make" followed by "(g)make install"<br />
**************************************************<br />
* Build and Install:<br />
make <br />
sudo make install<br />
<br />
==== Recent experiences ====<br />
I successfully installed the latest version on Mac OS 10.5 by:<br />
* Installing Macports.<br />
* <tt>sudo port install ghc</tt><br />
* <tt>sudo port install gtk2hs</tt> - which does not complete successfully. It does however, install the appropriate dependencies. Note that there are so many, you may need to install a couple of times due to time outs etc.. The build of Gtk2HS will fail, but that is ok - continue as below.<br />
* Remove the build directory under <tt>/opt/.../build/gtk2hs</tt><br />
* Download Gtk2Hs via darcs as per [http://haskell.org/gtk2hs/development/#darcs the gtk2hs download instructions]<br />
* do a <tt>sudo port install automake</tt><br />
* do a <tt>sudo port install alex</tt><br />
* do a <tt>sudo port install happy</tt> (Note this also fails and must be built from source. See the [[Happy]] page for details.)<br />
* Follow the build instructions on the [http://haskell.org/gtk2hs/development/#darcs the gtk2hs download page]. I would suggest using <tt>./configure --prefix=/opt/local</tt> to get it in the same place as ports - personal preference though.<br />
Good luck - as usual, your mileage may vary.<br />
<br />
== Demos ==<br />
<br />
=== OpenGL and Gtk2Hs ===<br />
<br />
[[Gtk2Hs/Demos/GtkGLext/hello.hs]]<br />
<br />
[[Gtk2Hs/Demos/GtkGLext/terrain.hs]] requires [[Gtk2Hs/Demos/GtkGLext/terrain.xpm]]<br />
<br />
==FAQs==<br />
These are links to FAQS on the main site.<br />
*[http://haskell.org/gtk2hs/archives/2005/06/23/hiding-the-console-on-windows/#more-26 Hiding the console on windows]<br />
*[http://haskell.org/gtk2hs/archives/2005/07/24/writing-multi-threaded-guis/#more-38 Writing multi-threaded GUIs]<br />
*[http://haskell.org/gtk2hs/archives/2005/06/24/building-from-source-on-windows/#more-15 Building on Windows]<br />
*[http://haskell.org/gtk2hs/development/#darcs Checkout instructions]. Also see [[Darcs]]<br />
<br />
[[Category:Applications]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=User_talk:BrettGiles&diff=25058User talk:BrettGiles2008-12-19T02:35:46Z<p>BrettGiles: Remove old outdated argument :)</p>
<hr />
<div></div>BrettGileshttps://wiki.haskell.org/index.php?title=Gtk2Hs&diff=24969Gtk2Hs2008-12-17T17:22:13Z<p>BrettGiles: /* Mac OS X */ Add recent experience</p>
<hr />
<div>[[Category:User interfaces]]<br />
== What is it? ==<br />
<br />
Gtk2Hs is a Haskell binding to Gtk+ 2.x.<br />
Using it, one can write Gtk+ based applications with GHC.<br />
<br />
== Homepage ==<br />
<br />
http://haskell.org/gtk2hs/<br />
<br />
== Status ==<br />
<br />
It currently works with Gtk+ 2.0 through to 2.8 on Unix, Win32 and MacOS X.<br />
The widget function coverage is almost complete, only a few minor bits and pieces are missing.<br />
<br />
It currently builds with ghc 5.04.3 through to 6.8.2<br />
<br />
== Installation Notes ==<br />
=== Mac OS X ===<br />
==== Article as of Mid 2008 ====<br />
Installing Gtk2Hs on Mac requires some finesse, at least until Haskell Libary Platform is built or ghc-6.8.3 is <br />
available in macports. (These are planned for late 2008.)<br />
<br />
* Install [http://macports.org MacPorts]<br />
* Install dependencies:<br />
sudo port instll glade3 libglade2 gstreamer gst-plugins-base gtksourceview cairo librsvg gtkglext firefox<br />
* Update PKG_CONFIG_PATH (for libraries)<br />
export PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig:/opt/local/lib/pkgconfig<br />
* Update ghc to use macports libs: Edit your main <tt>ghc</tt> driver program and change the last line to:<br />
exec $GHCBIN $TOPDIROPT ${1+"$@"} -L/opt/local/lib -I/opt/local/include<br />
* Download Gtk2Hs following instructions at [http://www.haskell.org/gtk2hs/downloads/ Gtk2Hs Download page]<br />
* Check configuration:<br />
./configure --enable-docs --enable-profiling<br />
<br />
...<br />
<br />
**************************************************<br />
* Configuration completed successfully. <br />
* <br />
* The following packages will be built: <br />
* <br />
* glib : yes <br />
* gtk : yes <br />
* glade : yes <br />
* cairo : yes <br />
* svgcairo : yes <br />
* gtkglext : yes <br />
* gconf : yes <br />
* sourceview : yes <br />
* mozembed : yes <br />
* soegtk : yes <br />
* gnomevfs : yes <br />
* gstreamer : yes <br />
* documentation : yes <br />
* <br />
* Now do "(g)make" followed by "(g)make install"<br />
**************************************************<br />
* Build and Install:<br />
make <br />
sudo make install<br />
==== Recent experiences ====<br />
I successfully installed the latest version on Mac OS 10.5 by:<br />
* Installing Macports.<br />
* <tt>sudo port install ghc</tt><br />
* <tt>sudo port install gtk2hs</tt> - which does not complete successfully. It does however, install the appropriate dependencies. Note that there are so many, you may need to install a couple of times due to time outs etc.. The build of Gtk2HS will fail, but that is ok - continue as below.<br />
* Remove the build directory under <tt>/opt/.../build/gtk2hs</tt><br />
* Download Gtk2Hs via darcs as per [http://haskell.org/gtk2hs/development/#darcs the gtk2hs download instructions]<br />
* do a <tt>sudo port install automake</tt><br />
* do a <tt>sudo port install alex</tt><br />
* do a <tt>sudo port install happy</tt> (Note this also fails and must be built from source. See the [[Happy]] page for details.)<br />
* Follow the build instructions on the [http://haskell.org/gtk2hs/development/#darcs the gtk2hs download page]. I would suggest using <tt>./configure --prefix=/opt/local</tt> to get it in the same place as ports - personal preference though.<br />
Good luck - as usual, your mileage may vary.<br />
<br />
== Demos ==<br />
<br />
=== OpenGL and Gtk2Hs ===<br />
<br />
[[Gtk2Hs/Demos/GtkGLext/hello.hs]]<br />
<br />
[[Gtk2Hs/Demos/GtkGLext/terrain.hs]] requires [[Gtk2Hs/Demos/GtkGLext/terrain.xpm]]<br />
<br />
==FAQs==<br />
These are links to FAQS on the main site.<br />
*[http://haskell.org/gtk2hs/archives/2005/06/23/hiding-the-console-on-windows/#more-26 Hiding the console on windows]<br />
*[http://haskell.org/gtk2hs/archives/2005/07/24/writing-multi-threaded-guis/#more-38 Writing multi-threaded GUIs]<br />
*[http://haskell.org/gtk2hs/archives/2005/06/24/building-from-source-on-windows/#more-15 Building on Windows]<br />
*[http://haskell.org/gtk2hs/development/#darcs Checkout instructions]. Also see [[Darcs]]<br />
<br />
[[Category:Applications]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=Gtk2Hs&diff=24968Gtk2Hs2008-12-17T17:07:54Z<p>BrettGiles: Adding link to various FAQs or other Gtk2hs pages</p>
<hr />
<div>[[Category:User interfaces]]<br />
== What is it? ==<br />
<br />
Gtk2Hs is a Haskell binding to Gtk+ 2.x.<br />
Using it, one can write Gtk+ based applications with GHC.<br />
<br />
== Homepage ==<br />
<br />
http://haskell.org/gtk2hs/<br />
<br />
== Status ==<br />
<br />
It currently works with Gtk+ 2.0 through to 2.8 on Unix, Win32 and MacOS X.<br />
The widget function coverage is almost complete, only a few minor bits and pieces are missing.<br />
<br />
It currently builds with ghc 5.04.3 through to 6.8.2<br />
<br />
== Installation Notes ==<br />
=== Mac OS X ===<br />
Installing Gtk2Hs on Mac requires some finesse, at least until Haskell Libary Platform is built or ghc-6.8.3 is <br />
available in macports. (These are planned for late 2008.)<br />
<br />
* Install [http://macports.org MacPorts]<br />
* Install dependencies:<br />
sudo port instll glade3 libglade2 gstreamer gst-plugins-base gtksourceview cairo librsvg gtkglext firefox<br />
* Update PKG_CONFIG_PATH (for libraries)<br />
export PKG_CONFIG_PATH=/usr/lib/pkgconfig:/usr/local/lib/pkgconfig:/opt/local/lib/pkgconfig<br />
* Update ghc to use macports libs: Edit your main <tt>ghc</tt> driver program and change the last line to:<br />
exec $GHCBIN $TOPDIROPT ${1+"$@"} -L/opt/local/lib -I/opt/local/include<br />
* Download Gtk2Hs following instructions at [http://www.haskell.org/gtk2hs/downloads/ Gtk2Hs Download page]<br />
* Check configuration:<br />
./configure --enable-docs --enable-profiling<br />
<br />
...<br />
<br />
**************************************************<br />
* Configuration completed successfully. <br />
* <br />
* The following packages will be built: <br />
* <br />
* glib : yes <br />
* gtk : yes <br />
* glade : yes <br />
* cairo : yes <br />
* svgcairo : yes <br />
* gtkglext : yes <br />
* gconf : yes <br />
* sourceview : yes <br />
* mozembed : yes <br />
* soegtk : yes <br />
* gnomevfs : yes <br />
* gstreamer : yes <br />
* documentation : yes <br />
* <br />
* Now do "(g)make" followed by "(g)make install"<br />
**************************************************<br />
* Build and Install:<br />
make <br />
sudo make install<br />
<br />
== Demos ==<br />
<br />
=== OpenGL and Gtk2Hs ===<br />
<br />
[[Gtk2Hs/Demos/GtkGLext/hello.hs]]<br />
<br />
[[Gtk2Hs/Demos/GtkGLext/terrain.hs]] requires [[Gtk2Hs/Demos/GtkGLext/terrain.xpm]]<br />
<br />
==FAQs==<br />
These are links to FAQS on the main site.<br />
*[http://haskell.org/gtk2hs/archives/2005/06/23/hiding-the-console-on-windows/#more-26 Hiding the console on windows]<br />
*[http://haskell.org/gtk2hs/archives/2005/07/24/writing-multi-threaded-guis/#more-38 Writing multi-threaded GUIs]<br />
*[http://haskell.org/gtk2hs/archives/2005/06/24/building-from-source-on-windows/#more-15 Building on Windows]<br />
*[http://haskell.org/gtk2hs/development/#darcs Checkout instructions]. Also see [[Darcs]]<br />
<br />
[[Category:Applications]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=Foldable_and_Traversable&diff=20653Foldable and Traversable2008-04-20T16:00:41Z<p>BrettGiles: Add links, surround code with hask, categorize</p>
<hr />
<div>[[Category:Code]] [[Category:Idioms]]<br />
<br />
<center>'''Notes on Foldable, Traversable and other useful classes'''</center><br />
<center>'' or "Where is Data.Sequence.toList?"''</center><br />
<br />
Data.Sequence is recommended as an efficient alternative to [list]s,<br />
with a more symmetric feel and better complexity on various<br />
operations.<br />
<br />
When you've been using it for a little while, there seem to be some<br />
baffling omissions from the API. The first couple you are likely to<br />
notice are the absence of "<hask>map</hask>" and "<hask>toList</hask>".<br />
<br />
The answer to these lies in the long list of instances which Sequence<br />
has. The Sequence version of map is "<hask>fmap</hask>", which comes from the<br />
Functor class. The Sequence version of <hask>toList</hask> is in the <hask>Foldable</hask> [[class]].<br />
<br />
When working with <hask>Sequence</hask> you also want to refer to the documentation<br />
for at least <hask>Foldable</hask> and <hask>Traversable</hask>. <hask>Functor</hask> only has the single<br />
[[method]], so we've already covered that.<br />
<br />
==What do these classes all mean? A brief tour:==<br />
<br />
===<hask>Functor</hask>===<br />
<br />
A [[functor]] is simply a [[container]]. Given a container, and a [[function]]<br />
which works on the elements, we can apply that function to each<br />
element. For lists, the familiar "<hask>map</hask>" does exactly this.<br />
<br />
Note that the function can produce elements of a different [[type]], so we<br />
may have a different type at the end.<br />
<br />
Examples:<br />
<br />
<haskell><br />
Prelude Data.Sequence> map (\n -> replicate n 'a') [1,3,5]<br />
["a","aaa","aaaaa"]<br />
Prelude Data.Sequence> fmap (\n -> replicate n 'a') (1 <| 3 <| 5 <| empty)<br />
fromList ["a","aaa","aaaaa"]<br />
</haskell><br />
<br />
===Foldable===<br />
<br />
A <hask>Foldable</hask> [[type]] is also a [[container]] (although the [[class]] does not<br />
technically require <hask>Functor</hask>, interesting <hask>Foldable</hask>s are all <hask>Functor</hask>s). It is a container with the added property that its items<br />
can be 'folded' to a summary value. In other words, it is a type which<br />
supports "<hask>foldr</hask>".<br />
<br />
Once you support <hask>foldr</hask>, of course, you can be turned into a list, by<br />
using <hask>foldr (:) []</hask>. This means that all <hask>Foldable</hask>s have a<br />
representation as a list; however the order of the items may or may<br />
not have any particular significance. In particular if a <hask>Foldable<hask> is<br />
also a <hask>Functor</hask>, <hask>toList</hask> and <hask>fmap</hask> need not perfectly commute; the list<br />
given ''after'' the <hask>fmap</hask> may be in a different order to the list<br />
''before'' the <hask>fmap</hask>. In the particular case of <hask>Data.Sequence</hask>, though,<br />
there '''is''' a well defined order and it is preserved as expected by<br />
<hask>fmap</hask> and exposed by <hask>toList</hask>.<br />
<br />
A particular kind of fold well-used by Haskell programmers is<br />
<hask>mapM_</hask>, which is a kind of fold over<br />
<hask>(>>)</hask>, and <hask>Foldable</hask> provides this along with the<br />
related <hask>sequence_</hask>.<br />
<br />
===Traversable===<br />
<br />
A <hask>Traversable</hask> [[type]] is a kind of upgraded <hask>Foldable</hask>. Where <hask>Foldable</hask><br />
gives you the ability to go through the structure processing the<br />
elements (<hask>foldr</hask>) but throwing away the shape, <hask>Traversable</hask> allows you<br />
to do that whilst preserving the shape and, e.g., putting new values<br />
in.<br />
<br />
<hask>Traversable</hask> is what we need for <hask>mapM</hask> and<br />
<hask>sequence</hask> : note the apparently surprising fact that the<br />
"_" versions are in a different [[typeclass]].<br />
<br />
== Some trickier functions: concatMap and filter ==<br />
<br />
Neither <hask>Traversable</hask> nor <hask>Foldable</hask> contain elements for <hask>concatMap</hask> and <hask>filter</hask>. That is because <hask>Foldable</hask> is about tearing down the structure<br />
completely, while <hask>Traversable</hask> is about preserving the structure<br />
exactly as-is. On the other hand <hask>concatMap</hask> tries to<br />
'squeeze more elements in' at a place and <hask>filter</hask> tries to<br />
cut them out.<br />
<br />
You can write <hask>concatMap</hask> for <hask>Sequence</hask> as follows:<br />
<br />
<haskell><br />
concatMap :: (a -> Seq b) -> Seq a -> Seq b<br />
concatMap = foldMap<br />
</haskell><br />
<br />
But why does it work? It works because sequence is an instance of<hask>Monoid</hask>, where the [[monoid]]al operation is "appending". The same<br />
definition works for lists, and we can write it more generally as:<br />
<br />
<haskell><br />
concatMap :: (Foldable f, Monoid (f b)) => (a -> f b) -> f a -> f b<br />
concatMap = foldMap<br />
</haskell><br />
<br />
And that works with lists and sequences both. Does it work with any<br />
Monoid which is Foldable? Only if the Monoid 'means the right<br />
thing'. If you have <hask>toList (f `mappend` g) = toList f ++ toList g</hask> then it definitely makes sense. In fact this easy to write<br />
condition is stronger than needed; it would be good enough if they<br />
were permutations of each other.<br />
<br />
<hask>filter</hask> turns out to be slightly harder still. You need<br />
something like 'singleton' (from <hask>Sequence</hask>), or <hask>\a -> [a]</hask><br />
for lists. We can use <hask>pure</hask> from <hask>Applicative</hask>, although<br />
it's not really right to bring <hask>Applicative</hask> in for this, and get:<br />
<br />
<haskell><br />
filter :: (Applicative f, Foldable f, Monoid (f a)) => <br />
(a -> Bool) -> f a -> f a<br />
filter p = foldMap (\a -> if p a then pure a else mempty)<br />
</haskell><br />
<br />
It's interesting to note that, under these conditions, we have a candidate<br />
to help us turn the <hask>Foldable</hask> into a <hask>Monad</hask>, since <hask>concatMap</hask> is a good<br />
definition for <hask>>>=</hask>, and we can use <hask>pure</hask> for <hask>return</hask>.<br />
<br />
== Generalising zipWith ==<br />
<br />
Another really useful list [[combinator]] that doesn't appear in the<br />
interfaces for <hask>Sequence</hask>, <hask>Foldable</hask> or <hask>Traversable</hask> is <hask>zipWith</hask>. The most general kind of <hask>zipWith</hask> over <hask>Traversable</hask>s will keep the exact shape of<br />
the <hask>Traversable</hask> on the left, whilst zipping against the values on the right. It turns out you can get away with a <hask>Foldable</hask> on the right, but you need to use a <hask>Monad</hask> (or an <hask>Applicative</hask>, actually) to thread the<br />
values through:<br />
<br />
<haskell><br />
import Prelude hiding (sequence)<br />
<br />
import Data.Sequence<br />
import Data.Foldable<br />
import Data.Traversable<br />
import Control.Applicative<br />
<br />
<br />
data Supply s v = Supply { unSupply :: [s] -> ([s],v) }<br />
<br />
instance Functor (Supply s) where <br />
fmap f av = Supply (\l -> let (l',v) = unSupply av l in (l',f v))<br />
<br />
instance Applicative (Supply s) where<br />
pure v = Supply (\l -> (l,v))<br />
af <*> av = Supply (\l -> let (l',f) = unSupply af l<br />
(l'',v) = unSupply av l'<br />
in (l'',f v))<br />
<br />
runSupply :: (Supply s v) -> [s] -> v<br />
runSupply av l = snd $ unSupply av l<br />
<br />
supply :: Supply s s<br />
supply = Supply (\(x:xs) -> (xs,x))<br />
<br />
zipTF :: (Traversable t, Foldable f) => t a -> f b -> t (a,b)<br />
zipTF t f = runSupply (traverse (\a -> (,) a <$> supply) t) (toList f)<br />
<br />
zipWithTF :: (Traversable t,Foldable f) => (a -> b -> c) -> t a -> f b -> t c<br />
zipWithTF g t f = runSupply (traverse (\a -> g a <$> supply) t) (toList f)<br />
<br />
zipWithTFM :: (Traversable t,Foldable f,Monad m) => <br />
(a -> b -> m c) -> t a -> f b -> m (t c)<br />
zipWithTFM g t f = sequence (zipWithTF g t f)<br />
<br />
zipWithTFA :: (Traversable t,Foldable f,Applicative m) => <br />
(a -> b -> m c) -> t a -> f b -> m (t c)<br />
zipWithTFA g t f = sequenceA (zipWithTF g t f)<br />
</haskell><br />
<br />
The code above fails with a [[pattern match]] error when the <hask>Foldable</hask> container doesn't have enough input. Here is an alternative version which provides friendlier error reports and makes use of <hask>State</hask> instead of the self defined Supply [[monad]].<br />
<br />
<haskell><br />
module GenericZip <br />
(zipWithTF,<br />
zipTF,<br />
zipWithTFA,<br />
zipWithTFM) where<br />
<br />
<br />
import Data.Foldable<br />
import Data.Traversable<br />
import qualified Data.Traversable as T<br />
import Control.Applicative<br />
import Control.Monad.State <br />
<br />
-- | The state contains the list of values obtained form the foldable container<br />
-- and a String indicating the name of the function currectly being executed<br />
data ZipState a = ZipState {fName :: String,<br />
list :: [a]}<br />
<br />
-- | State monad containing ZipState<br />
type ZipM l a = State (ZipState l) a<br />
<br />
-- | pops the first element of the list inside the state<br />
pop :: ZipM l l<br />
pop = do <br />
st <- get <br />
let xs = list st<br />
n = fName st<br />
case xs of<br />
(a:as) -> do put st{list=as}<br />
return a<br />
[] -> error $ n ++ ": insufficient input"<br />
<br />
-- | pop a value form the state and supply it to the second <br />
-- argument of a binary function <br />
supplySecond :: (a -> b -> c) -> a -> ZipM b c<br />
supplySecond f a = do b <- pop <br />
return $ f a b<br />
<br />
zipWithTFError :: (Traversable t,Foldable f) => <br />
String -> (a -> b -> c) -> t a -> f b -> t c <br />
zipWithTFError str g t f = evalState (T.mapM (supplySecond g) t) <br />
(ZipState str (toList f))<br />
<br />
<br />
zipWithTF :: (Traversable t,Foldable f) => (a -> b -> c) -> t a -> f b -> t c<br />
zipWithTF = zipWithTFError "GenericZip.zipWithTF"<br />
<br />
zipTF :: (Traversable t, Foldable f) => t a -> f b -> t (a,b)<br />
zipTF = zipWithTFError "GenericZip.zipTF" (,) <br />
<br />
<br />
zipWithTFM :: (Traversable t,Foldable f,Monad m) => <br />
(a -> b -> m c) -> t a -> f b -> m (t c)<br />
zipWithTFM g t f = T.sequence (zipWithTFError "GenericZip.zipWithTFM" g t f)<br />
<br />
zipWithTFA :: (Traversable t,Foldable f,Applicative m) => <br />
(a -> b -> m c) -> t a -> f b -> m (t c)<br />
zipWithTFA g t f = sequenceA (zipWithTFError "GenericZip.zipWithTFA" g t f)<br />
</haskell></div>BrettGileshttps://wiki.haskell.org/index.php?title=FoldableAndTraversable&diff=20650FoldableAndTraversable2008-04-20T15:41:35Z<p>BrettGiles: FoldableAndTraversable moved to Foldable and Traversable: Following naming guidelines</p>
<hr />
<div>#redirect [[Foldable and Traversable]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=Talk:Foldable_and_Traversable&diff=20651Talk:Foldable and Traversable2008-04-20T15:41:35Z<p>BrettGiles: Talk:FoldableAndTraversable moved to Talk:Foldable and Traversable</p>
<hr />
<div>==Rename and tidy==<br />
Unless the original authors object before hand, on 2008-04-20, I'll rename and tidy this page to follow [[HaskellWiki:Guidelines |Guidelines re page editing and formatting]]--[[User:BrettGiles|BrettGiles]] 17:00, 16 April 2008 (UTC)</div>BrettGileshttps://wiki.haskell.org/index.php?title=Talk:FoldableAndTraversable&diff=20652Talk:FoldableAndTraversable2008-04-20T15:41:35Z<p>BrettGiles: Talk:FoldableAndTraversable moved to Talk:Foldable and Traversable: Following naming guidelines</p>
<hr />
<div>#redirect [[Talk:Foldable and Traversable]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=Foldable_and_Traversable&diff=20649Foldable and Traversable2008-04-20T15:41:35Z<p>BrettGiles: FoldableAndTraversable moved to Foldable and Traversable</p>
<hr />
<div>=Notes on Foldable, Traversable and other useful classes=<br />
<center>'' or "Where is Data.Sequence.toList?"''</center><br />
<br />
Data.Sequence is recommended as an efficient alternative to lists,<br />
with a more symmetric feel and better complexity on various<br />
operations.<br />
<br />
When you've been using it for a little while, there seem to be some<br />
baffling omissions from the API. The first couple you are likely to<br />
notice are the absence of "map" and "toList".<br />
<br />
The answer to these lies in the long list of instances which Sequence<br />
has. The Sequence version of map is "fmap", which comes from the<br />
Functor class. The Sequence version of toList is in the Foldable<br />
class.<br />
<br />
When working with Sequence you also want to refer to the documentation<br />
for at least Foldable and Traversable. Functor only has the single<br />
method, so we've already covered that.<br />
<br />
==What do these classes all mean? A brief tour:==<br />
<br />
===Functor===<br />
<br />
A functor is simply a container. Given a container, and a function<br />
which works on the elements, we can apply that function to each<br />
element. For lists, the familiar "map" does exactly this.<br />
<br />
Note that the function can produce elements of a different type, so we<br />
may have a different type at the end.<br />
<br />
Examples:<br />
<br />
<haskell><br />
Prelude Data.Sequence> map (\n -> replicate n 'a') [1,3,5]<br />
["a","aaa","aaaaa"]<br />
Prelude Data.Sequence> fmap (\n -> replicate n 'a') (1 <| 3 <| 5 <| empty)<br />
fromList ["a","aaa","aaaaa"]<br />
</haskell><br />
<br />
===Foldable===<br />
<br />
A Foldable type is also a container (although the class does not<br />
technically require Functor, interesting Foldables are all<br />
Functors). It is a container with the added property that its items<br />
can be 'folded' to a summary value. In other words, it is a type which<br />
supports "foldr".<br />
<br />
Once you support foldr, of course, you can be turned into a list, by<br />
using <hask>foldr (:) []</hask>. This means that all Foldables have a<br />
representation as a list; however the order of the items may or may<br />
not have any particular significance. In particular if a Foldable is<br />
also a Functor, toList and fmap need not perfectly commute; the list<br />
given ''after'' the fmap may be in a different order to the list<br />
''before'' the fmap. In the particular case of Data.Sequence, though,<br />
there *is* a well defined order and it is preserved as expected by<br />
fmap and exposed by toList.<br />
<br />
A particular kind of fold well-used by haskell programmers is<br />
<hask>mapM_</hask>, which is a kind of fold over<br />
<hask>(>>)</hask>, and Foldable provides this along with the<br />
related <hask>sequence_</hask>.<br />
<br />
===Traversable===<br />
<br />
A Traversable type is a kind of upgraded Foldable. Where Foldable<br />
gives you the ability to go through the structure processing the<br />
elements (foldr) but throwing away the shape, Traversable allows you<br />
to do that whilst preserving the shape and, e.g., putting new values<br />
in.<br />
<br />
Traversable is what we need for <hask>mapM</hask> and<br />
<hask>sequence</hask> : note the apparently surprising fact that the<br />
"_" versions are in a different typeclass.<br />
<br />
== Some trickier functions: concatMap and filter ==<br />
<br />
Neither Traversable nor Foldable contain elements for concatMap and<br />
filter. That is because Foldable is about tearing down the structure<br />
completely, while Traversable is about preserving the structure<br />
exactly as-is. On the other hand <hask>concatMap</hask> tries to<br />
'squeeze more elements in' at a place and <hask>filter</hask> tries to<br />
cut them out.<br />
<br />
You can write concatMap for Sequence as follows:<br />
<br />
<haskell><br />
concatMap :: (a -> Seq b) -> Seq a -> Seq b<br />
concatMap = foldMap<br />
</haskell><br />
<br />
But why does it work? It works because sequence is an instance of<br />
Monoid, where the monoidal operation is "appending". The same<br />
definition works for lists, and we can write it more generally as:<br />
<br />
<haskell><br />
concatMap :: (Foldable f, Monoid (f b)) => (a -> f b) -> f a -> f b<br />
concatMap = foldMap<br />
</haskell><br />
<br />
And that works with lists and sequences both. Does it work with any<br />
Monoid which is Foldable? Only if the Monoid 'means the right<br />
thing'. If you have <hask>toList (f `mappend` g) = toList f ++ toList g</hask> then it definitely makes sense. In fact this easy to write<br />
condition is stronger than needed; it would be good enough if they<br />
were permutations of each other.<br />
<br />
<hask>filter</hask> turns out to be slightly harder still. You need<br />
something like 'singleton' (from Sequence), or <hask>\a -> [a]</hask><br />
for lists. We can use <hask>pure</hask> from Applicative, although<br />
it's not really right to bring Applicative in for this, and get:<br />
<br />
<haskell><br />
filter :: (Applicative f, Foldable f, Monoid (f a)) => <br />
(a -> Bool) -> f a -> f a<br />
filter p = foldMap (\a -> if p a then pure a else mempty)<br />
</haskell><br />
<br />
It's interesting to note that, under these conditions, we have a candidate<br />
to help us turn the Foldable into a Monad, since concatMap is a good<br />
definition for <hask>>>=</hask>, and we can use pure for return.<br />
<br />
== Generalising zipWith ==<br />
<br />
Another really useful list combinator that doesn't appear in the<br />
interfaces for Sequence, Foldable or Traversable is zipWith. The most<br />
general kind of zipWith over Traversables will keep the exact shape of<br />
the Traversable on the left, whilst zipping against the values on the<br />
right. It turns out you can get away with a Foldable on the right, but<br />
you need to use a Monad (or an Applicative, actually) to thread the<br />
values through:<br />
<br />
<haskell><br />
import Prelude hiding (sequence)<br />
<br />
import Data.Sequence<br />
import Data.Foldable<br />
import Data.Traversable<br />
import Control.Applicative<br />
<br />
<br />
data Supply s v = Supply { unSupply :: [s] -> ([s],v) }<br />
<br />
instance Functor (Supply s) where <br />
fmap f av = Supply (\l -> let (l',v) = unSupply av l in (l',f v))<br />
<br />
instance Applicative (Supply s) where<br />
pure v = Supply (\l -> (l,v))<br />
af <*> av = Supply (\l -> let (l',f) = unSupply af l<br />
(l'',v) = unSupply av l'<br />
in (l'',f v))<br />
<br />
runSupply :: (Supply s v) -> [s] -> v<br />
runSupply av l = snd $ unSupply av l<br />
<br />
supply :: Supply s s<br />
supply = Supply (\(x:xs) -> (xs,x))<br />
<br />
zipTF :: (Traversable t, Foldable f) => t a -> f b -> t (a,b)<br />
zipTF t f = runSupply (traverse (\a -> (,) a <$> supply) t) (toList f)<br />
<br />
zipWithTF :: (Traversable t,Foldable f) => (a -> b -> c) -> t a -> f b -> t c<br />
zipWithTF g t f = runSupply (traverse (\a -> g a <$> supply) t) (toList f)<br />
<br />
zipWithTFM :: (Traversable t,Foldable f,Monad m) => <br />
(a -> b -> m c) -> t a -> f b -> m (t c)<br />
zipWithTFM g t f = sequence (zipWithTF g t f)<br />
<br />
zipWithTFA :: (Traversable t,Foldable f,Applicative m) => <br />
(a -> b -> m c) -> t a -> f b -> m (t c)<br />
zipWithTFA g t f = sequenceA (zipWithTF g t f)<br />
</haskell><br />
<br />
The code above fails with a pattern match error when the foldable container doesn't have enough input. Here is an alternative version which provides friendlier error reports and makes use of State instead of the self defined Supply monad.<br />
<br />
<haskell><br />
module GenericZip <br />
(zipWithTF,<br />
zipTF,<br />
zipWithTFA,<br />
zipWithTFM) where<br />
<br />
<br />
import Data.Foldable<br />
import Data.Traversable<br />
import qualified Data.Traversable as T<br />
import Control.Applicative<br />
import Control.Monad.State <br />
<br />
-- | The state contains the list of values obtained form the foldable container<br />
-- and a String indicating the name of the function currectly being executed<br />
data ZipState a = ZipState {fName :: String,<br />
list :: [a]}<br />
<br />
-- | State monad containing ZipState<br />
type ZipM l a = State (ZipState l) a<br />
<br />
-- | pops the first element of the list inside the state<br />
pop :: ZipM l l<br />
pop = do <br />
st <- get <br />
let xs = list st<br />
n = fName st<br />
case xs of<br />
(a:as) -> do put st{list=as}<br />
return a<br />
[] -> error $ n ++ ": insufficient input"<br />
<br />
-- | pop a value form the state and supply it to the second <br />
-- argument of a binary function <br />
supplySecond :: (a -> b -> c) -> a -> ZipM b c<br />
supplySecond f a = do b <- pop <br />
return $ f a b<br />
<br />
zipWithTFError :: (Traversable t,Foldable f) => <br />
String -> (a -> b -> c) -> t a -> f b -> t c <br />
zipWithTFError str g t f = evalState (T.mapM (supplySecond g) t) <br />
(ZipState str (toList f))<br />
<br />
<br />
zipWithTF :: (Traversable t,Foldable f) => (a -> b -> c) -> t a -> f b -> t c<br />
zipWithTF = zipWithTFError "GenericZip.zipWithTF"<br />
<br />
zipTF :: (Traversable t, Foldable f) => t a -> f b -> t (a,b)<br />
zipTF = zipWithTFError "GenericZip.zipTF" (,) <br />
<br />
<br />
zipWithTFM :: (Traversable t,Foldable f,Monad m) => <br />
(a -> b -> m c) -> t a -> f b -> m (t c)<br />
zipWithTFM g t f = T.sequence (zipWithTFError "GenericZip.zipWithTFM" g t f)<br />
<br />
zipWithTFA :: (Traversable t,Foldable f,Applicative m) => <br />
(a -> b -> m c) -> t a -> f b -> m (t c)<br />
zipWithTFA g t f = sequenceA (zipWithTFError "GenericZip.zipWithTFA" g t f)<br />
</haskell></div>BrettGileshttps://wiki.haskell.org/index.php?title=CollaborativeFiltering&diff=20646CollaborativeFiltering2008-04-20T15:39:34Z<p>BrettGiles: CollaborativeFiltering moved to Collaborative filtering: follow guidelines</p>
<hr />
<div>#redirect [[Collaborative filtering]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=Talk:Collaborative_filtering&diff=20647Talk:Collaborative filtering2008-04-20T15:39:34Z<p>BrettGiles: Talk:CollaborativeFiltering moved to Talk:Collaborative filtering</p>
<hr />
<div>As per the guidelines, this probably should be named '''Collaborative filtering'''--[[User:BrettGiles|BrettGiles]] 22:11, 17 April 2008 (UTC)</div>BrettGileshttps://wiki.haskell.org/index.php?title=Talk:CollaborativeFiltering&diff=20648Talk:CollaborativeFiltering2008-04-20T15:39:34Z<p>BrettGiles: Talk:CollaborativeFiltering moved to Talk:Collaborative filtering: follow guidelines</p>
<hr />
<div>#redirect [[Talk:Collaborative filtering]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=Collaborative_filtering&diff=20645Collaborative filtering2008-04-20T15:39:33Z<p>BrettGiles: CollaborativeFiltering moved to Collaborative filtering</p>
<hr />
<div>[[Category:Code]] [[Category:Idioms]]This page was added to discuss different versions of the code for collaborative filtering at [http://www.serpentine.com/blog/2007/08/27/weighted-slope-one-in-haskell-collaborative-filtering-in-29-lines-of-code/#comment-75580 Bryan's blog].<br />
<br />
== Chris' version ==<br />
<br />
I renamed the variables and then reorganized the code a bit.<br />
<br />
The(update,SlopeOne,predict) definitions can be compared with the newer (update2,SlopeOne',predict') definitions.<br />
<br />
<haskell><br />
module WeightedSlopeOne (Rating, SlopeOne, empty, predict, update) where<br />
<br />
import Data.List (foldl',foldl1')<br />
import qualified Data.Map as M<br />
<br />
-- The item type is a polymorphic parameter. Since it goes into a Map<br />
-- it must be able to be compared, so item must be an instance of Ord.<br />
type Count = Int<br />
type RatingValue = Double<br />
-- The Rating is the known (item,Rating) information for a particular "user"<br />
type Rating item = M.Map item RatingValue<br />
<br />
-- The SlopeOne matrix is indexed by pairs of items and is implemented<br />
-- as a sparse map of maps.<br />
newtype SlopeOne item = SlopeOne (M.Map item (M.Map item (Count,RatingValue)))<br />
deriving (Show)<br />
<br />
-- The SlopeOne' matrix is an un-normalized version of SlopeOne<br />
newtype SlopeOne' item = SlopeOne' (M.Map item (M.Map item (Count,RatingValue)))<br />
deriving (Show)<br />
<br />
empty = SlopeOne M.empty<br />
empty' = SlopeOne' M.empty<br />
<br />
-- This performs a strict addition on pairs made of two nuumeric types<br />
addT (a,b) (c,d) = let (l,r) = (a+c, b+d) in l `seq` r `seq` (l, r)<br />
<br />
<br />
-- There is never an entry for the "diagonal" elements with equal<br />
-- items in the pair: (foo,foo) is never in the SlopeOne.<br />
update :: Ord item => SlopeOne item -> [Rating item] -> SlopeOne item<br />
update (SlopeOne matrixInNormed) usersRatings =<br />
SlopeOne . M.map (M.map norm) . foldl' update' matrixIn $ usersRatings<br />
where update' oldMatrix userRatings =<br />
foldl' (\oldMatrix (itemPair, rating) -> insert oldMatrix itemPair rating)<br />
oldMatrix itemCombos<br />
where itemCombos = [ ((item1, item2), (1, rating1 - rating2)) <br />
| (item1, rating1) <- ratings<br />
, (item2, rating2) <- ratings<br />
, item1 /= item2]<br />
ratings = M.toList userRatings<br />
insert outerMap (item1, item2) newRating = M.insertWith' outer item1 newOuterEntry outerMap<br />
where newOuterEntry = M.singleton item2 newRating<br />
outer _ innerMap = M.insertWith' addT item2 newRating innerMap<br />
norm (count,total_rating) = (count, total_rating / fromIntegral count)<br />
un_norm (count,rating) = (count, rating * fromIntegral count)<br />
matrixIn = M.map (M.map un_norm) matrixInNormed<br />
<br />
<br />
-- This version of update2 makes an unnormalize slopeOne' from each<br />
-- Rating and combines them using Map.union* operations and addT.<br />
update2 :: Ord item => SlopeOne' item -> [Rating item] -> SlopeOne' item<br />
update2 s@(SlopeOne' matrixIn) usersRatingsIn | null usersRatings = s<br />
| otherwise =<br />
SlopeOne' . M.unionsWith (M.unionWith addT) . (matrixIn:) . map fromRating $ usersRatings<br />
where usersRatings = filter ((1<) . M.size) usersRatingsIn<br />
fromRating userRating = M.mapWithKey expand1 userRating<br />
where expand1 item1 rating1 = M.mapMaybeWithKey expand2 userRating<br />
where expand2 item2 rating2 | item1 == item2 = Nothing<br />
| otherwise = Just (1,rating1 - rating2)<br />
<br />
predict :: Ord a => SlopeOne a -> Rating a -> Rating a<br />
predict (SlopeOne matrixIn) userRatings =<br />
let freqM = foldl' insert M.empty<br />
[ (item1,found_rating,user_rating)<br />
| (item1,innerMap) <- M.assocs matrixIn<br />
, M.notMember item1 userRatings<br />
, (user_item, user_rating) <- M.toList userRatings<br />
, item1 /= user_item<br />
, found_rating <- M.lookup user_item innerMap<br />
]<br />
insert oldM (item1,found_rating,user_rating) =<br />
let (count,norm_rating) = found_rating<br />
total_rating = fromIntegral count * (norm_rating + user_rating)<br />
in M.insertWith' addT item1 (count,total_rating) oldM<br />
normM = M.map (\(count, total_rating) -> total_rating / fromIntegral count) freqM<br />
in M.filter (\norm_rating -> norm_rating > 0) normM<br />
<br />
-- This is a modified version of predict. It also expect the<br />
-- unnormalized SlopeOne' but this is a small detail<br />
predict' :: Ord a => SlopeOne' a -> Rating a -> Rating a<br />
predict' (SlopeOne' matrixIn) userRatings =<br />
M.mapMaybe calcItem (M.difference matrixIn userRatings)<br />
where calcItem innerMap | M.null combined = Nothing<br />
| norm_rating <= 0 = Nothing<br />
| otherwise = Just norm_rating<br />
where combined = M.intersectionWith weight innerMap userRatings<br />
(total_count,total_rating) = foldl1' addT (M.elems combined)<br />
norm_rating = total_rating / fromIntegral total_count<br />
weight (count,rating) user_rating =<br />
(count,rating + fromIntegral count * user_rating)<br />
<br />
userData :: [Rating String]<br />
userData = map M.fromList [<br />
[("squid", 1.0), ("cuttlefish", 0.5), ("octopus", 0.2)],<br />
[("squid", 1.0), ("octopus", 0.5), ("nautilus", 0.2)],<br />
[("squid", 0.2), ("octopus", 1.0), ("cuttlefish", 0.4), ("nautilus", 0.4)],<br />
[("cuttlefish", 0.9), ("octopus", 0.4), ("nautilus", 0.5)]<br />
]<br />
<br />
userInfo = M.fromList [("squid", 0.4),("cuttlefish",0.9),("dolphin",1.0)]<br />
<br />
predictions = predict (update empty userData) userInfo<br />
<br />
predictions' = predict' (update2 empty' userData) userInfo<br />
</haskell><br />
<br />
== More optimized storage ==<br />
<br />
The changes to SlopeOne/update/predict below use a different internal data structure for storing the sparse matrix of SlopeOne. Instead of a Map of Map design it uses a Map of List design and keeps the List in distinct ascending form. The list values are a strict (data Tup) type which should help save space compared to the previous inner Map design and yet efficiently provide all the operations needed by update and predict.<br />
<br />
Much of the logic of prediction is in the computeRating helper function.<br />
<br />
<haskell><br />
-- The SlopeOne matrix is indexed by pairs of items and is implemented<br />
-- as a sparse map of distinct ascending lists. The 'update' and<br />
-- 'predict' functions do not need the inner type to actually be a<br />
-- map, so the list saves space and complexity.<br />
newtype SlopeOne item = SlopeOne (M.Map item [Tup item])<br />
deriving (Show)<br />
<br />
-- Strict triple tuple type for SlopeOne internals<br />
data Tup item = Tup { itemT :: !item, countT :: !Count, ratingT :: !RatingValue }<br />
deriving (Show)<br />
<br />
empty :: SlopeOne item<br />
empty = SlopeOne M.empty<br />
<br />
update :: Ord item => SlopeOne item -> [Rating item] -> SlopeOne item<br />
update s@(SlopeOne matrixIn) usersRatingsIn | null usersRatings = s<br />
| otherwise =<br />
SlopeOne . M.unionsWith mergeAdd . (matrixIn:) . map fromRating $ usersRatings<br />
where usersRatings = filter ((1<) . M.size) usersRatingsIn<br />
-- fromRating converts a Rating into a Map of Lists, a singleton SlopeOne.<br />
fromRating userRatings = M.mapWithKey expand userRatings<br />
where expand item1 rating1 = map makeTup . M.toAscList . M.delete item1 $ userRatings<br />
where makeTup (item2,rating2) = Tup item2 1 (rating1-rating2)<br />
<br />
-- 'mergeAdd' is a helper for 'update'.<br />
-- Optimized traversal of distinct ascending lists to perform additive merge.<br />
mergeAdd :: Ord item => [Tup item] -> [Tup item] -> [Tup item]<br />
mergeAdd !xa@(x:xs) !ya@(y:ys) =<br />
case compare (itemT x) (itemT y) of<br />
LT -> x : mergeAdd xs ya<br />
GT -> y : mergeAdd xa ys<br />
EQ -> Tup (itemT x) (countT x + countT y) (ratingT x + ratingT y) : mergeAdd xs ys<br />
mergeAdd xs [] = xs<br />
mergeAdd [] ys = ys<br />
<br />
-- The output Rating has no items in common with the input Rating and<br />
-- only includes positively weighted ratings.<br />
predict :: Ord item => SlopeOne item -> Rating item -> Rating item<br />
predict (SlopeOne matrixIn) userRatings =<br />
M.mapMaybe (computeRating ratingList) (M.difference matrixIn userRatings)<br />
where ratingList = M.toAscList userRatings<br />
<br />
-- 'computeRating' is a helper for 'predict'.<br />
-- Optimized traversal of distinct ascending lists to compute positive weighted rating.<br />
computeRating :: (Ord item) => [(item,RatingValue)] -> [Tup item] -> Maybe RatingValue<br />
computeRating !xa@(x:xs) !ya@(y:ys) =<br />
case compare (fst x) (itemT y) of<br />
LT -> computeRating xs ya<br />
GT -> computeRating xa ys<br />
EQ -> helper (countT y) (ratingT y + fromIntegral (countT y) * snd x) xs ys<br />
where<br />
helper :: (Ord item) => Count -> RatingValue -> [(item,RatingValue)] -> [Tup item] -> Maybe RatingValue<br />
helper !count !rating !xa@(x:xs) !ya@(y:ys) =<br />
case compare (fst x) (itemT y) of<br />
LT -> helper count rating xs ya<br />
GT -> helper count rating xa ys<br />
EQ -> helper (count + countT y) (rating + ratingT y + fromIntegral (countT y) * (snd x)) xs ys<br />
helper !count !rating _ _ | rating > 0 = Just (rating / fromIntegral count)<br />
| otherwise = Nothing<br />
computeRating _ _ = Nothing<br />
</haskell></div>BrettGileshttps://wiki.haskell.org/index.php?title=Talk:Collaborative_filtering&diff=20605Talk:Collaborative filtering2008-04-17T22:11:06Z<p>BrettGiles: Rename warning / thought</p>
<hr />
<div>As per the guidelines, this probably should be named '''Collaborative filtering'''--[[User:BrettGiles|BrettGiles]] 22:11, 17 April 2008 (UTC)</div>BrettGileshttps://wiki.haskell.org/index.php?title=Collaborative_filtering&diff=20604Collaborative filtering2008-04-17T22:10:03Z<p>BrettGiles: Categorized</p>
<hr />
<div>[[Category:Code]] [[Category:Idioms]]This page was added to discuss different versions of the code for collaborative filtering at [http://www.serpentine.com/blog/2007/08/27/weighted-slope-one-in-haskell-collaborative-filtering-in-29-lines-of-code/#comment-75580 Bryan's blog].<br />
<br />
== Chris' version ==<br />
<br />
I renamed the variables and then reorganized the code a bit.<br />
<br />
The(update,SlopeOne,predict) definitions can be compared with the newer (update2,SlopeOne',predict') definitions.<br />
<br />
<haskell><br />
module WeightedSlopeOne (Rating, SlopeOne, empty, predict, update) where<br />
<br />
import Data.List (foldl',foldl1')<br />
import qualified Data.Map as M<br />
<br />
-- The item type is a polymorphic parameter. Since it goes into a Map<br />
-- it must be able to be compared, so item must be an instance of Ord.<br />
type Count = Int<br />
type RatingValue = Double<br />
-- The Rating is the known (item,Rating) information for a particular "user"<br />
type Rating item = M.Map item RatingValue<br />
<br />
-- The SlopeOne matrix is indexed by pairs of items and is implemented<br />
-- as a sparse map of maps.<br />
newtype SlopeOne item = SlopeOne (M.Map item (M.Map item (Count,RatingValue)))<br />
deriving (Show)<br />
<br />
-- The SlopeOne' matrix is an un-normalized version of SlopeOne<br />
newtype SlopeOne' item = SlopeOne' (M.Map item (M.Map item (Count,RatingValue)))<br />
deriving (Show)<br />
<br />
empty = SlopeOne M.empty<br />
empty' = SlopeOne' M.empty<br />
<br />
-- This performs a strict addition on pairs made of two nuumeric types<br />
addT (a,b) (c,d) = let (l,r) = (a+c, b+d) in l `seq` r `seq` (l, r)<br />
<br />
<br />
-- There is never an entry for the "diagonal" elements with equal<br />
-- items in the pair: (foo,foo) is never in the SlopeOne.<br />
update :: Ord item => SlopeOne item -> [Rating item] -> SlopeOne item<br />
update (SlopeOne matrixInNormed) usersRatings =<br />
SlopeOne . M.map (M.map norm) . foldl' update' matrixIn $ usersRatings<br />
where update' oldMatrix userRatings =<br />
foldl' (\oldMatrix (itemPair, rating) -> insert oldMatrix itemPair rating)<br />
oldMatrix itemCombos<br />
where itemCombos = [ ((item1, item2), (1, rating1 - rating2)) <br />
| (item1, rating1) <- ratings<br />
, (item2, rating2) <- ratings<br />
, item1 /= item2]<br />
ratings = M.toList userRatings<br />
insert outerMap (item1, item2) newRating = M.insertWith' outer item1 newOuterEntry outerMap<br />
where newOuterEntry = M.singleton item2 newRating<br />
outer _ innerMap = M.insertWith' addT item2 newRating innerMap<br />
norm (count,total_rating) = (count, total_rating / fromIntegral count)<br />
un_norm (count,rating) = (count, rating * fromIntegral count)<br />
matrixIn = M.map (M.map un_norm) matrixInNormed<br />
<br />
<br />
-- This version of update2 makes an unnormalize slopeOne' from each<br />
-- Rating and combines them using Map.union* operations and addT.<br />
update2 :: Ord item => SlopeOne' item -> [Rating item] -> SlopeOne' item<br />
update2 s@(SlopeOne' matrixIn) usersRatingsIn | null usersRatings = s<br />
| otherwise =<br />
SlopeOne' . M.unionsWith (M.unionWith addT) . (matrixIn:) . map fromRating $ usersRatings<br />
where usersRatings = filter ((1<) . M.size) usersRatingsIn<br />
fromRating userRating = M.mapWithKey expand1 userRating<br />
where expand1 item1 rating1 = M.mapMaybeWithKey expand2 userRating<br />
where expand2 item2 rating2 | item1 == item2 = Nothing<br />
| otherwise = Just (1,rating1 - rating2)<br />
<br />
predict :: Ord a => SlopeOne a -> Rating a -> Rating a<br />
predict (SlopeOne matrixIn) userRatings =<br />
let freqM = foldl' insert M.empty<br />
[ (item1,found_rating,user_rating)<br />
| (item1,innerMap) <- M.assocs matrixIn<br />
, M.notMember item1 userRatings<br />
, (user_item, user_rating) <- M.toList userRatings<br />
, item1 /= user_item<br />
, found_rating <- M.lookup user_item innerMap<br />
]<br />
insert oldM (item1,found_rating,user_rating) =<br />
let (count,norm_rating) = found_rating<br />
total_rating = fromIntegral count * (norm_rating + user_rating)<br />
in M.insertWith' addT item1 (count,total_rating) oldM<br />
normM = M.map (\(count, total_rating) -> total_rating / fromIntegral count) freqM<br />
in M.filter (\norm_rating -> norm_rating > 0) normM<br />
<br />
-- This is a modified version of predict. It also expect the<br />
-- unnormalized SlopeOne' but this is a small detail<br />
predict' :: Ord a => SlopeOne' a -> Rating a -> Rating a<br />
predict' (SlopeOne' matrixIn) userRatings =<br />
M.mapMaybe calcItem (M.difference matrixIn userRatings)<br />
where calcItem innerMap | M.null combined = Nothing<br />
| norm_rating <= 0 = Nothing<br />
| otherwise = Just norm_rating<br />
where combined = M.intersectionWith weight innerMap userRatings<br />
(total_count,total_rating) = foldl1' addT (M.elems combined)<br />
norm_rating = total_rating / fromIntegral total_count<br />
weight (count,rating) user_rating =<br />
(count,rating + fromIntegral count * user_rating)<br />
<br />
userData :: [Rating String]<br />
userData = map M.fromList [<br />
[("squid", 1.0), ("cuttlefish", 0.5), ("octopus", 0.2)],<br />
[("squid", 1.0), ("octopus", 0.5), ("nautilus", 0.2)],<br />
[("squid", 0.2), ("octopus", 1.0), ("cuttlefish", 0.4), ("nautilus", 0.4)],<br />
[("cuttlefish", 0.9), ("octopus", 0.4), ("nautilus", 0.5)]<br />
]<br />
<br />
userInfo = M.fromList [("squid", 0.4),("cuttlefish",0.9),("dolphin",1.0)]<br />
<br />
predictions = predict (update empty userData) userInfo<br />
<br />
predictions' = predict' (update2 empty' userData) userInfo<br />
</haskell><br />
<br />
== More optimized storage ==<br />
<br />
The changes to SlopeOne/update/predict below use a different internal data structure for storing the sparse matrix of SlopeOne. Instead of a Map of Map design it uses a Map of List design and keeps the List in distinct ascending form. The list values are a strict (data Tup) type which should help save space compared to the previous inner Map design and yet efficiently provide all the operations needed by update and predict.<br />
<br />
Much of the logic of prediction is in the computeRating helper function.<br />
<br />
<haskell><br />
-- The SlopeOne matrix is indexed by pairs of items and is implemented<br />
-- as a sparse map of distinct ascending lists. The 'update' and<br />
-- 'predict' functions do not need the inner type to actually be a<br />
-- map, so the list saves space and complexity.<br />
newtype SlopeOne item = SlopeOne (M.Map item [Tup item])<br />
deriving (Show)<br />
<br />
-- Strict triple tuple type for SlopeOne internals<br />
data Tup item = Tup { itemT :: !item, countT :: !Count, ratingT :: !RatingValue }<br />
deriving (Show)<br />
<br />
empty :: SlopeOne item<br />
empty = SlopeOne M.empty<br />
<br />
update :: Ord item => SlopeOne item -> [Rating item] -> SlopeOne item<br />
update s@(SlopeOne matrixIn) usersRatingsIn | null usersRatings = s<br />
| otherwise =<br />
SlopeOne . M.unionsWith mergeAdd . (matrixIn:) . map fromRating $ usersRatings<br />
where usersRatings = filter ((1<) . M.size) usersRatingsIn<br />
-- fromRating converts a Rating into a Map of Lists, a singleton SlopeOne.<br />
fromRating userRatings = M.mapWithKey expand userRatings<br />
where expand item1 rating1 = map makeTup . M.toAscList . M.delete item1 $ userRatings<br />
where makeTup (item2,rating2) = Tup item2 1 (rating1-rating2)<br />
<br />
-- 'mergeAdd' is a helper for 'update'.<br />
-- Optimized traversal of distinct ascending lists to perform additive merge.<br />
mergeAdd :: Ord item => [Tup item] -> [Tup item] -> [Tup item]<br />
mergeAdd !xa@(x:xs) !ya@(y:ys) =<br />
case compare (itemT x) (itemT y) of<br />
LT -> x : mergeAdd xs ya<br />
GT -> y : mergeAdd xa ys<br />
EQ -> Tup (itemT x) (countT x + countT y) (ratingT x + ratingT y) : mergeAdd xs ys<br />
mergeAdd xs [] = xs<br />
mergeAdd [] ys = ys<br />
<br />
-- The output Rating has no items in common with the input Rating and<br />
-- only includes positively weighted ratings.<br />
predict :: Ord item => SlopeOne item -> Rating item -> Rating item<br />
predict (SlopeOne matrixIn) userRatings =<br />
M.mapMaybe (computeRating ratingList) (M.difference matrixIn userRatings)<br />
where ratingList = M.toAscList userRatings<br />
<br />
-- 'computeRating' is a helper for 'predict'.<br />
-- Optimized traversal of distinct ascending lists to compute positive weighted rating.<br />
computeRating :: (Ord item) => [(item,RatingValue)] -> [Tup item] -> Maybe RatingValue<br />
computeRating !xa@(x:xs) !ya@(y:ys) =<br />
case compare (fst x) (itemT y) of<br />
LT -> computeRating xs ya<br />
GT -> computeRating xa ys<br />
EQ -> helper (countT y) (ratingT y + fromIntegral (countT y) * snd x) xs ys<br />
where<br />
helper :: (Ord item) => Count -> RatingValue -> [(item,RatingValue)] -> [Tup item] -> Maybe RatingValue<br />
helper !count !rating !xa@(x:xs) !ya@(y:ys) =<br />
case compare (fst x) (itemT y) of<br />
LT -> helper count rating xs ya<br />
GT -> helper count rating xa ys<br />
EQ -> helper (count + countT y) (rating + ratingT y + fromIntegral (countT y) * (snd x)) xs ys<br />
helper !count !rating _ _ | rating > 0 = Just (rating / fromIntegral count)<br />
| otherwise = Nothing<br />
computeRating _ _ = Nothing<br />
</haskell></div>BrettGileshttps://wiki.haskell.org/index.php?title=Amb&diff=20601Amb2008-04-17T22:05:14Z<p>BrettGiles: Categorize</p>
<hr />
<div>[[Category:Monad]] [[Category:Code]] [[Category:Idioms]]<br />
This is an implementation of the [http://www.randomhacks.net/articles/2005/10/11/amb-operator <code>amb</code> operator] in Haskell. Interestingly, it is identical to the list monad: remove 'amb' and the examples below work fine (apart, of course, from the IO one).<br />
<br />
Notably, AmbT could be considered [[ListT done right]].<br />
<br />
<haskell><br />
module Amb (AmbT, Amb, amb, cut, runAmbT, runAmb) where<br />
<br />
import Control.Monad.Cont<br />
import Control.Monad.State<br />
import Control.Monad.Identity<br />
<br />
newtype AmbT r m a = AmbT { unAmbT :: StateT [AmbT r m r] (ContT r m) a }<br />
type Amb r = AmbT r Identity<br />
<br />
instance MonadTrans (AmbT r) where<br />
lift = AmbT . lift . lift<br />
<br />
instance (Monad m) => Monad (AmbT r m) where<br />
AmbT a >>= b = AmbT $ a >>= unAmbT . b<br />
return = AmbT . return<br />
<br />
backtrack :: (Monad m) => AmbT r m a<br />
backtrack = do xss <- AmbT get<br />
case xss of<br />
[] -> fail "amb tree exhausted"<br />
(f:xs) -> do AmbT $ put xs; f; return undefined<br />
<br />
addPoint :: (Monad m) => (() -> AmbT r m r) -> AmbT r m ()<br />
addPoint x = AmbT $ modify (x () :)<br />
<br />
amb :: (Monad m) => [a] -> AmbT r m a<br />
amb [] = backtrack<br />
amb (x:xs) = ambCC $ \exit -> do<br />
ambCC $ \k -> addPoint k >> exit x<br />
amb xs<br />
where ambCC f = AmbT $ callCC $ \k -> unAmbT $ f $ AmbT . k<br />
<br />
cut :: (Monad m) => AmbT r m ()<br />
cut = AmbT $ put []<br />
<br />
runAmbT :: (Monad m) => AmbT r m r -> m r<br />
runAmbT (AmbT a) = runContT (evalStateT a []) return<br />
<br />
runAmb :: Amb r r -> r<br />
runAmb = runIdentity . runAmbT<br />
</haskell><br />
<br />
And some examples:<br />
<br />
<haskell><br />
example :: Amb r (Integer,Integer)<br />
example = do x <- amb [1,2,3]<br />
y <- amb [4,5,6]<br />
if x*y == 8<br />
then return (x,y)<br />
else amb []<br />
<br />
factor :: Integer -> Amb r (Integer,Integer)<br />
factor a = do x <- amb [2..]<br />
y <- amb [2..x]<br />
if x*y == a<br />
then return (x,y)<br />
else amb []<br />
<br />
factorIO :: Integer -> AmbT r IO (Integer,Integer)<br />
factorIO a = do lift $ putStrLn $ "Factoring " ++ show a<br />
x <- amb [2..]<br />
y <- amb [2..x]<br />
lift $ putStrLn $ "Trying " ++ show x ++ " and " ++ show y<br />
if x*y == a<br />
then do lift $ putStrLn "Found it!"<br />
return (x,y)<br />
else do lift $ putStrLn $ "Nope (" ++ show (x*y) ++ ")"<br />
amb []<br />
</haskell><br />
<br />
The extra 'r' can be avoided if you're not using strict Haskell-98:<br />
<br />
<haskell><br />
type AmbT' m a = forall r. AmbT r m a<br />
type Amb' a = AmbT' Identity a<br />
</haskell></div>BrettGileshttps://wiki.haskell.org/index.php?title=Talk:Foldable_and_Traversable&diff=20574Talk:Foldable and Traversable2008-04-16T17:00:44Z<p>BrettGiles: Rename warning</p>
<hr />
<div>==Rename and tidy==<br />
Unless the original authors object before hand, on 2008-04-20, I'll rename and tidy this page to follow [[HaskellWiki:Guidelines |Guidelines re page editing and formatting]]--[[User:BrettGiles|BrettGiles]] 17:00, 16 April 2008 (UTC)</div>BrettGileshttps://wiki.haskell.org/index.php?title=User:BrettGiles&diff=16130User:BrettGiles2007-10-09T18:18:40Z<p>BrettGiles: A sad wikignome with little time</p>
<hr />
<div>'''Brett Giles'''<br />
{{Foundations infobox}}<br />
Grad Student in Formal Methods at the University of Calgary.<br />
<br />
A proud wikignome - who unfortunately finds that full-time Ph.D. studies + full-time job leaves little or no time for gnoming. :(<br />
<br />
[http://pages.cpsc.ucalgary.ca/~gilesb U of C home page]<br />
<br />
[http://drogar.blogspot.com/search/label/Haskell My blogs related to Haskell]<br />
<br />
__NOTOC__<br />
== Haskell interests ==<br />
<br />
Compilers: Currently make lots of use of [[Alex]] and [[Happy]].<br />
<br />
Currently working on a compiler and simulator for a quantum programming language, using [[Gtk2Hs]] as the visualization tool.<br />
<br />
==Haskell mode for XEmacs==<br />
I use [[Haskell mode for Emacs]] on XEmacs. So far, on all the linux systems that I have tried it on (admittedly, only Ubuntu and Debian), there is a system function missing that interferes with automatic indenting. Secondly, there seems to be an issue with setting the haskell default face to nil.<br />
<br />
===line-end-position===<br />
<br />
To fix this, find where the haskell mode package is installed on your system. (Usually <code>/usr/share/emacs/site-lisp/haskell-mode</code>). Edit the file <code>haskell-indent.el</code> and add the lines:<br />
<pre-lisp><br />
(eval-and-compile<br />
<br />
;; If `line-end-position' isn't available provide one.<br />
(unless (fboundp 'line-end-position)<br />
(defun line-end-position (&optional n)<br />
"Return the `point' of the end of the current line."<br />
(save-excursion<br />
(end-of-line n)<br />
(point))))<br />
</pre-lisp><br />
right after the comments at the top. That should fix the issue.<br />
<br />
===haskell-default-face===<br />
<br />
This one shows up when typing in code (at various spots - most often when typing a qualified function, such as <hask>List.map</hask>.)<br />
<br />
To fix this one, edit the file <code>haskell-font-lock.el</code>. Look for the line that says:<br />
<pre-lisp><br />
(defvar haskell-default-face nil)<br />
</pre-lisp><br />
and change this to <br />
<pre-lisp><br />
(defvar haskell-default-face 'default)<br />
</pre-lisp><br />
In my version, this is line 168.<br />
<br />
Then, look for the line that says:<br />
<pre-lisp><br />
(,qvarid 0 haskell-default-face)<br />
</pre-lisp><br />
and change it to<br />
<pre-lisp><br />
(,qvarid 0 (symbol-value 'haskell-default-face))<br />
</pre-lisp><br />
<br />
For me, this is line 326 of the file.<br />
YMMV - hope this helps.<br />
<br />
==License of contributions==<br />
<br />
<br />
I hereby license all my contributions to this wiki, and the old hawiki, under the simple permissive license on [[HaskellWiki:Copyrights]] &mdash; [[User:BrettGiles|BrettGiles]] 03:14, 2 March 2006 (UTC)<br />
<br />
<br />
==Reverting spam==<br />
<br />
If you find some spam - the easiest way to undo it is use the "diff" on the recent changes page (selecting the first spam change). Then, click on the "Revison as of yyyy-mm ..." link on the left side. This will show the page as it was before the spam edit. <br />
<br />
Then, edit the page and save it as is (Please indicate you are reverting spam in the Summary). WikiPedia will warn you when you edit that this is an old version. But that is what you want - so go ahead and save it.<br />
<br />
==Links in the WIKI==<br />
*[[HaskellWiki:Guidelines |Guidelines re page editing and formatting]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=User_talk:ChrisKuklewicz&diff=15326User talk:ChrisKuklewicz2007-08-29T12:40:41Z<p>BrettGiles: Note about page naming</p>
<hr />
<div>Chris, your concurrency discussion should go on a sub page, not the main<br />
concurrency page. People trying to find out about GHC's concurrency<br />
mechanisms will only be distracted by this. (Good work though!) [[User:DonStewart|dons]] 16:12, 8 December 2006 (UTC)<br />
<br />
Don, I have moved it to the sub page [[GHC/Concurrency/Flaws]]. Thanks for the encouragement. I originally thought I "knew" how it worked but in answering on the mailing list I actually tried things that proved I was wrong. How can we open a trac ticket / bug report? -- [[User:ChrisKuklewicz|ChrisKuklewicz]] 17:09, 8 December 2006 (UTC)<br />
<br />
Hi Chris. The new page you put up, [[CollaborativeFiltering]], should be named "Collaborative filtering" to fit in with the [[HaskellWiki:Guidelines]].--[[User:BrettGiles|BrettGiles]] 12:40, 29 August 2007 (UTC)</div>BrettGileshttps://wiki.haskell.org/index.php?title=Multi-parameter_type_class&diff=15304Multi-parameter type class2007-08-28T17:23:24Z<p>BrettGiles: /* About */ minor wibble</p>
<hr />
<div>[[Category:Language extensions]]<br />
[[Category:Stub articles]]<br />
<br />
<br />
== About ==<br />
<br />
Basically, [[type]] [[class]]es which can take multiple arguments, such as:<br />
<br />
<hask><br />
class Foo a b<br />
</hask><br />
<br />
Without [[functional dependencies]] or [[associated types]], these multi-parameter type classes may cause too much ambiguity to pass the type-checker.<br />
<br />
== Also see ==<br />
<br />
[http://hackage.haskell.org/trac/haskell-prime/wiki/MultiParamTypeClasses The Haskell' page]</div>BrettGileshttps://wiki.haskell.org/index.php?title=HaskellWiki_talk:Guidelines&diff=15254HaskellWiki talk:Guidelines2007-08-24T20:10:11Z<p>BrettGiles: Does anyone have any comments to make about the proposal....</p>
<hr />
<div>==Headlines==<br />
<br />
[[User:BrettGiles|Brett]], this is not to offend you. It just expresses my conviction. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]]<br />
<br />
:Not to worry [[User:Wolfgang Jeltsch|Wolfgang]] - I never take offence :) - My thoughts on the usage of level 2 only were primarily due to the size balance, but also I note this is a guideline for the original mediawiki site. Does anyone know why that is? [[User:BrettGiles|BrettGiles]] 22:11, 25 February 2006 (UTC)<br />
<br />
::No idea, but it seems loose to me. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 22:40, 25 February 2006 (UTC)<br />
<br />
:::I did some research on [http://meta.wikimedia.org/wiki/Help_talk:Section metawiki] and this is the reason they start at level 2. ''"So that when a user without CSS, or a text-mode browser, or a screen reader visits, they'll be presented with a page that at least has a logical document flow."'' From what I can tell, by default, the page title is rendered as a '''h1''' element. So are single '''=''' headings. Double '''==''' are '''h2''' and so on. So from that point of view it does make sense to start at two equals. I think the real issue is that the software is slightly broken in not generating an '''h2''' for a single equals sign. So, what do you think? [[User:BrettGiles|BrettGiles]] 22:36, 26 February 2006 (UTC)<br />
<br />
::::I prefer starting with ==, like Wikipedia. &mdash;[[User:Ashley Y|Ashley Y]] 00:52, 2 March 2006 (UTC)<br />
<br />
::::MediaWiki is broken in not creating an '''h2''' element for a headline with single equal signs. So we should work around this brokeness by making our top-level headlines <tt>==</tt> headlines. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 21:22, 8 March 2006 (UTC)<br />
<br />
:::::I've added a respective section to [[HaskellWiki:Guidelines]]. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 21:40, 8 March 2006 (UTC)<br />
<br />
==Page nameing and renaming==<br />
Apparently the last rename I did so offended the author that they quit the wiki. I used to follow the guideline I just added on the main page, but had never got a response before. However, considering the size of the wiki and the number of new users (especially those that seem to not know there are guidelines :), perhaps it is time to re-institute the practice. --[[User:BrettGiles|BrettGiles]] 18:04, 24 July 2007 (UTC)<br />
<br />
==Official guidelines?==<br />
<br />
What makes a guidline an "official" guidline? What's the process? &mdash;[[User:Ashley Y|Ashley Y]] 00:53, 2 March 2006 (UTC)<br />
<br />
:I suspect that a large number of the users / contributors to this site have an academic background. My experience with academia is that some kind of consensus based decision is the most successful at getting the decision adopted. In a community like this wiki, I’m not sure how to get that. We could send out notices on the various mailing lists, we could post notes on the front page and probably other ways as well. Like any consensus decision making it would take a long time. On the other hand, those that support the site could just be autocratic, set the rule and if there is too much flak, change it. <br />
:As to what actually makes an "official" guidline, I think it is up to the '''sysops''' whether we even have such a thing. The word tends to mean that '''sysops''' are required to monitor and fix the site when these are not followed. So, we might not even want to go to official, stay at unofficial and just let the community grow the guidlines (and do the monitoring) as they see fit. Sometimes, a certain level of anarchy works fine.[[User:BrettGiles|BrettGiles]] 16:06, 2 March 2006 (UTC)<br />
::I think that the traditional consensus decision making process is too slow. In addition, not everyone is interested in every guideline question, so it is not sensible to bother everyone with each of these questions. Therefore, it seems to me that it is better to follow your “autocracy approach”. And I also doubt that it is sensible to let some sysops decide about what guidelines are official. At least, this would be a bit contrary to the wiki approach, in my opinion. So I propose that users are allowed to set up guidelines they think of as sensible—possibly after some short discussion—and to declare them as official. If others don't like the guidelines, the guidelines can still be discussed (again) and changed. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 21:22, 8 March 2006 (UTC)<br />
:::So this is how all that started: with an abuse of power. Is this real? I mean, it really started this way? Do you understand that autocracy is against the very wiki philosophy and is an abuse against every other wiki users? Users are not allowed to set rules and start enforcing them '''against''' other users. This is going to create tension and, in the long run, to destroy a wiki. --AndreaRossato Thu 26 2007 07:37 CEST <br />
<br />
OK. Everything on the project page should have a consensus. Everything else should be discussed here. I have adjusted the project page accordingly. &mdash;[[User:Ashley Y|Ashley Y]] 06:34, 3 March 2006 (UTC)<br />
:What is the “project page”? -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 21:22, 8 March 2006 (UTC)<br />
::Ah, I understand. It's [[HaskellWiki:Guidelines]]. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 21:40, 8 March 2006 (UTC)<br />
<br />
== Headlines ==<br />
<br />
Each page has a title which is automatically shown near the top of the page (currently centered and in red). So it doesn't make sense to put a single level 1 headline at the top of the page. (At the moment, you will see this on a few pages of this wiki. I suppose this is a legacy which comes from copying content from the old website to this wiki.)<br />
<br />
For top-level structuring, level 1 headlines (the ones denoted by single equals signs in the source) should be used. It is semantically incorrect to use level 2 headlines for this purpose. I note that level 1 headlines are currently rather large and in a font that might not be preferable. However, the solution to this is not to refrain from using level 1 headlines but to change the stylesheet appropriately. ''&mdash;says [[User:Wolfgang Jeltsch]]''<br />
<br />
:Note that is is currently being discussed. Level 1 (single equals) create an <tt>&lt;h1&gt;</tt> heading, which is the same level as the page title. We may (or may not:) switch to the standard of starting at level 2 (double equals) ''&mdash;says [[User:BrettGiles]]''<br />
<br />
:I prefer starting with level 2 as per Wikipedia. I consider the page title to be implicitly level 1 (whether it gets rendered as h1 or not). &mdash;[[User:Ashley Y|Ashley Y]] 06:34, 3 March 2006 (UTC)<br />
<br />
<br />
== Wiki Bug ==<br />
Try giving a Haskell example with the greater than or the less than sign in it. It clashes with the HTML rendering! -- says [[User:Uchchwhash|Pirated Dreams]] 04:22, 17 March 2006 (UTC)<br />
<br />
==What's Wrong With This Guidelines==<br />
I don't know how these guidelines became the official policy of this<br />
wiki, and I cannot find out how some of us decided to become the<br />
housekeepers, or the [http://c2.com/cgi/wiki?WikiGnome WikiGnome]s, of<br />
it.<br />
<br />
Still I've been involved in wiki development and I have some ideas on<br />
how a wiki should work. I tried to discuss it in the<br />
[http://www.haskell.org/pipermail/haskell-cafe/2007-July/029483.html haskell-café mailing list].<br />
<br />
Probably I should do that here too.<br />
<br />
[http://c2.com/cgi/wiki?HowToReactToGoodStyleTransgressions How to react to good style transgression?]<br />
Are these guidelines to be enforced? Aren't enforced guidelines a<br />
contradiction in terms? Sure they are...<br />
<br />
I don't think that cosmetic edits done just to enforce these<br />
guidelines are going to help this wiki on the long run. They piss<br />
newcomers off. And you are pissing off right the newcomers you would<br />
like to keep, the ones who are willing to contribute.<br />
<br />
You could start by reading the new material, and doing some edit to<br />
the content: if you collaborate the wiki way, probably your<br />
suggestions on style issues would be followed.<br />
<br />
Anyway, these are guidelines, or they pretend they are, and so you<br />
must always think about the fact the new paths can be taken.<br />
<br />
Instead what you have been doing, in the last year, is setting some<br />
rules here and reshaping the wiki in the name of those rules.<br />
<br />
===And what is right with these guidelines===<br />
So, when the "new" wiki started, there was quite a bit of discussion here and on the haskell list about what was an appropriate style for the wiki pages, considering that the site is meant to be a resource for new and exsisting Haskell users and as such, were desired to be reasonably consistent in style. These guidelines were the result. A variety of people edit pages to bring them into the stylistic guidelines, but if anyone is not happy with the current set, this seems like a good place to discuss changing them. <br />
<br />
Andrea's link to the "WikiGnome" has some very good pointers about stylistic changes being applied to the edits of ''newcomers'', and an even better one about dropping the argument. So this is my last edit about the subject :) --[[User:BrettGiles|BrettGiles]] 21:58, 25 July 2007 (UTC)<br />
:: Style consistency is not a primary goal of a wiki. A primary goal for the wiki is always having new people contribute to its grow. If you think that stylistic guidelines enforcing must be achieved regardless of the consequences than you should drop wiki technologies and use a blogging system or other kind of content management system. Instead, if you want to use a wiki, you should try to stick to the wiki philosophy as close as you can. --AndreaRossato Thu 26 2007 07:27 CEST <br />
::I'd like to point out that I perfectly understand that your effort has the aim of improving this wiki, and I don't think that style consistency is something to be avoided. What I'm trying to do, is to help finding a better way of achieving style consistency without increasing the level of entrance for new users. I hope you - Brett - will understand I have nothing against you. But I would like you to take into account the perspective of a newcomer too. I hope you are going to keep on discussing these issues with me. That would be helpful for the both of us. Thanks for your kind attention. --AndreaRossato Jul 26 2007 10:05 CEST. <br />
<br />
And that leads me to the second real big issue: page renaming.<br />
<br />
==Why Page Renaming Is BAD==<br />
<br />
Wiki page titles are [http://en.wikipedia.org/wiki/URI URI], and URI<br />
should be persistent over time.<br />
<br />
When you rename a page you are breaking URI persistence. A redirect is<br />
only a work around. A bad work around.<br />
<br />
You did a lot of page renaming lately. By doing so you broke a lot of<br />
URIs.<br />
<br />
You are also breaking the structure of this wiki, by creating a false<br />
hierarchy of pages. In a wiki all pages are top level. Hierarchy and<br />
wikis belong to different worlds.<br />
<br />
I do believe that this guidelines are used in a vary bad way. I would<br />
like you to stop. Or at least to seriously reconsider your way of<br />
enforcing them.<br />
<br />
AndreaRossato -- Wed Jul 25 2007 19:57 CEST<br />
<br />
==Amendments Proposal==<br />
I think we could use this episode to grow, as a community. I suggest some amendments to these guidelines:<br />
# enforcement: we could add something about guidelines enforcement, referring to the link I [http://c2.com/cgi/wiki?HowToReactToGoodStyleTransgressions posted before]: the user's Talk page should be used instead, and cosmetic edits should be ruled out as a bad practice, incompatible with the wiki philosopy;<br />
# page renaming: we should adopt a very strict policy for page renaming. URI persistence should be the primary goal, so page names can be changed only within a very short period of time after page creation, only for compelling reasons and only with the consent of other users, after discussing it in the talk page;<br />
# wiki structure: I'm not going to make any proposal but I would like you to think about the fact that wiki pages should be all top level, with no (false) hierarchy. This means that using slashes in page name should be considered bad practice.<br />
I hope I will find people willing to discuss these proposals.<br />
Thanks for your kind attention. --AndreaRossato Jul 26 07:59 CEST<br />
:Hi Andrea - I would suggest a few things regarding this:<br />
:*Let's move the proposal to the top of the page so that it is the first thing people see. We may even want to group the rest (or some of the rest) as old history.<br />
:*It might be a good idea to advertise this on the haskell mailing list and the haskell-cafe lists. Some people who are interested might not check the latest changes. Previous discussions seemed effective to me because there were multiple points of view.<br />
::--[[User:BrettGiles|BrettGiles]] 01:24, 27 July 2007 (UTC)<br />
:::So, a month has gone by with no changes / additions / updates to this page. I wonder if anyone supports or disagrees with the proposal by Andrea? --[[User:BrettGiles|BrettGiles]] 20:10, 24 August 2007 (UTC)</div>BrettGileshttps://wiki.haskell.org/index.php?title=User_talk:Green_tea&diff=15099User talk:Green tea2007-08-16T18:23:13Z<p>BrettGiles: Note about guidelines</p>
<hr />
<div>Hey Green Tea<br />
<br />
The new page you created, [[Metaphorless Monads]], I believe should actually be named Metaphorless monads. According to the [[HaskellWiki:Guidelines]], we like to use sentence case for page names (and section headers).--[[User:BrettGiles|BrettGiles]] 18:23, 16 August 2007 (UTC)</div>BrettGileshttps://wiki.haskell.org/index.php?title=HaskellWiki_talk:Guidelines&diff=14702HaskellWiki talk:Guidelines2007-07-27T01:24:49Z<p>BrettGiles: /* Amendments Proposal */ Starting a bit of meta-discussion.</p>
<hr />
<div>==Headlines==<br />
<br />
[[User:BrettGiles|Brett]], this is not to offend you. It just expresses my conviction. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]]<br />
<br />
:Not to worry [[User:Wolfgang Jeltsch|Wolfgang]] - I never take offence :) - My thoughts on the usage of level 2 only were primarily due to the size balance, but also I note this is a guideline for the original mediawiki site. Does anyone know why that is? [[User:BrettGiles|BrettGiles]] 22:11, 25 February 2006 (UTC)<br />
<br />
::No idea, but it seems loose to me. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 22:40, 25 February 2006 (UTC)<br />
<br />
:::I did some research on [http://meta.wikimedia.org/wiki/Help_talk:Section metawiki] and this is the reason they start at level 2. ''"So that when a user without CSS, or a text-mode browser, or a screen reader visits, they'll be presented with a page that at least has a logical document flow."'' From what I can tell, by default, the page title is rendered as a '''h1''' element. So are single '''=''' headings. Double '''==''' are '''h2''' and so on. So from that point of view it does make sense to start at two equals. I think the real issue is that the software is slightly broken in not generating an '''h2''' for a single equals sign. So, what do you think? [[User:BrettGiles|BrettGiles]] 22:36, 26 February 2006 (UTC)<br />
<br />
::::I prefer starting with ==, like Wikipedia. &mdash;[[User:Ashley Y|Ashley Y]] 00:52, 2 March 2006 (UTC)<br />
<br />
::::MediaWiki is broken in not creating an '''h2''' element for a headline with single equal signs. So we should work around this brokeness by making our top-level headlines <tt>==</tt> headlines. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 21:22, 8 March 2006 (UTC)<br />
<br />
:::::I've added a respective section to [[HaskellWiki:Guidelines]]. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 21:40, 8 March 2006 (UTC)<br />
<br />
==Page nameing and renaming==<br />
Apparently the last rename I did so offended the author that they quit the wiki. I used to follow the guideline I just added on the main page, but had never got a response before. However, considering the size of the wiki and the number of new users (especially those that seem to not know there are guidelines :), perhaps it is time to re-institute the practice. --[[User:BrettGiles|BrettGiles]] 18:04, 24 July 2007 (UTC)<br />
<br />
==Official guidelines?==<br />
<br />
What makes a guidline an "official" guidline? What's the process? &mdash;[[User:Ashley Y|Ashley Y]] 00:53, 2 March 2006 (UTC)<br />
<br />
:I suspect that a large number of the users / contributors to this site have an academic background. My experience with academia is that some kind of consensus based decision is the most successful at getting the decision adopted. In a community like this wiki, I’m not sure how to get that. We could send out notices on the various mailing lists, we could post notes on the front page and probably other ways as well. Like any consensus decision making it would take a long time. On the other hand, those that support the site could just be autocratic, set the rule and if there is too much flak, change it. <br />
:As to what actually makes an "official" guidline, I think it is up to the '''sysops''' whether we even have such a thing. The word tends to mean that '''sysops''' are required to monitor and fix the site when these are not followed. So, we might not even want to go to official, stay at unofficial and just let the community grow the guidlines (and do the monitoring) as they see fit. Sometimes, a certain level of anarchy works fine.[[User:BrettGiles|BrettGiles]] 16:06, 2 March 2006 (UTC)<br />
::I think that the traditional consensus decision making process is too slow. In addition, not everyone is interested in every guideline question, so it is not sensible to bother everyone with each of these questions. Therefore, it seems to me that it is better to follow your “autocracy approach”. And I also doubt that it is sensible to let some sysops decide about what guidelines are official. At least, this would be a bit contrary to the wiki approach, in my opinion. So I propose that users are allowed to set up guidelines they think of as sensible—possibly after some short discussion—and to declare them as official. If others don't like the guidelines, the guidelines can still be discussed (again) and changed. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 21:22, 8 March 2006 (UTC)<br />
:::So this is how all that started: with an abuse of power. Is this real? I mean, it really started this way? Do you understand that autocracy is against the very wiki philosophy and is an abuse against every other wiki users? Users are not allowed to set rules and start enforcing them '''against''' other users. This is going to create tension and, in the long run, to destroy a wiki. --AndreaRossato Thu 26 2007 07:37 CEST <br />
<br />
OK. Everything on the project page should have a consensus. Everything else should be discussed here. I have adjusted the project page accordingly. &mdash;[[User:Ashley Y|Ashley Y]] 06:34, 3 March 2006 (UTC)<br />
:What is the “project page”? -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 21:22, 8 March 2006 (UTC)<br />
::Ah, I understand. It's [[HaskellWiki:Guidelines]]. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 21:40, 8 March 2006 (UTC)<br />
<br />
== Headlines ==<br />
<br />
Each page has a title which is automatically shown near the top of the page (currently centered and in red). So it doesn't make sense to put a single level 1 headline at the top of the page. (At the moment, you will see this on a few pages of this wiki. I suppose this is a legacy which comes from copying content from the old website to this wiki.)<br />
<br />
For top-level structuring, level 1 headlines (the ones denoted by single equals signs in the source) should be used. It is semantically incorrect to use level 2 headlines for this purpose. I note that level 1 headlines are currently rather large and in a font that might not be preferable. However, the solution to this is not to refrain from using level 1 headlines but to change the stylesheet appropriately. ''&mdash;says [[User:Wolfgang Jeltsch]]''<br />
<br />
:Note that is is currently being discussed. Level 1 (single equals) create an <tt>&lt;h1&gt;</tt> heading, which is the same level as the page title. We may (or may not:) switch to the standard of starting at level 2 (double equals) ''&mdash;says [[User:BrettGiles]]''<br />
<br />
:I prefer starting with level 2 as per Wikipedia. I consider the page title to be implicitly level 1 (whether it gets rendered as h1 or not). &mdash;[[User:Ashley Y|Ashley Y]] 06:34, 3 March 2006 (UTC)<br />
<br />
<br />
== Wiki Bug ==<br />
Try giving a Haskell example with the greater than or the less than sign in it. It clashes with the HTML rendering! -- says [[User:Uchchwhash|Pirated Dreams]] 04:22, 17 March 2006 (UTC)<br />
<br />
==What's Wrong With This Guidelines==<br />
I don't know how these guidelines became the official policy of this<br />
wiki, and I cannot find out how some of us decided to become the<br />
housekeepers, or the [http://c2.com/cgi/wiki?WikiGnome WikiGnome]s, of<br />
it.<br />
<br />
Still I've been involved in wiki development and I have some ideas on<br />
how a wiki should work. I tried to discuss it in the<br />
[http://www.haskell.org/pipermail/haskell-cafe/2007-July/029483.html haskell-café mailing list].<br />
<br />
Probably I should do that here too.<br />
<br />
[http://c2.com/cgi/wiki?HowToReactToGoodStyleTransgressions How to react to good style transgression?]<br />
Are these guidelines to be enforced? Aren't enforced guidelines a<br />
contradiction in terms? Sure they are...<br />
<br />
I don't think that cosmetic edits done just to enforce these<br />
guidelines are going to help this wiki on the long run. They piss<br />
newcomers off. And you are pissing off right the newcomers you would<br />
like to keep, the ones who are willing to contribute.<br />
<br />
You could start by reading the new material, and doing some edit to<br />
the content: if you collaborate the wiki way, probably your<br />
suggestions on style issues would be followed.<br />
<br />
Anyway, these are guidelines, or they pretend they are, and so you<br />
must always think about the fact the new paths can be taken.<br />
<br />
Instead what you have been doing, in the last year, is setting some<br />
rules here and reshaping the wiki in the name of those rules.<br />
<br />
===And what is right with these guidelines===<br />
So, when the "new" wiki started, there was quite a bit of discussion here and on the haskell list about what was an appropriate style for the wiki pages, considering that the site is meant to be a resource for new and exsisting Haskell users and as such, were desired to be reasonably consistent in style. These guidelines were the result. A variety of people edit pages to bring them into the stylistic guidelines, but if anyone is not happy with the current set, this seems like a good place to discuss changing them. <br />
<br />
Andrea's link to the "WikiGnome" has some very good pointers about stylistic changes being applied to the edits of ''newcomers'', and an even better one about dropping the argument. So this is my last edit about the subject :) --[[User:BrettGiles|BrettGiles]] 21:58, 25 July 2007 (UTC)<br />
:: Style consistency is not a primary goal of a wiki. A primary goal for the wiki is always having new people contribute to its grow. If you think that stylistic guidelines enforcing must be achieved regardless of the consequences than you should drop wiki technologies and use a blogging system or other kind of content management system. Instead, if you want to use a wiki, you should try to stick to the wiki philosophy as close as you can. --AndreaRossato Thu 26 2007 07:27 CEST <br />
::I'd like to point out that I perfectly understand that your effort has the aim of improving this wiki, and I don't think that style consistency is something to be avoided. What I'm trying to do, is to help finding a better way of achieving style consistency without increasing the level of entrance for new users. I hope you - Brett - will understand I have nothing against you. But I would like you to take into account the perspective of a newcomer too. I hope you are going to keep on discussing these issues with me. That would be helpful for the both of us. Thanks for your kind attention. --AndreaRossato Jul 26 2007 10:05 CEST. <br />
<br />
And that leads me to the second real big issue: page renaming.<br />
<br />
==Why Page Renaming Is BAD==<br />
<br />
Wiki page titles are [http://en.wikipedia.org/wiki/URI URI], and URI<br />
should be persistent over time.<br />
<br />
When you rename a page you are breaking URI persistence. A redirect is<br />
only a work around. A bad work around.<br />
<br />
You did a lot of page renaming lately. By doing so you broke a lot of<br />
URIs.<br />
<br />
You are also breaking the structure of this wiki, by creating a false<br />
hierarchy of pages. In a wiki all pages are top level. Hierarchy and<br />
wikis belong to different worlds.<br />
<br />
I do believe that this guidelines are used in a vary bad way. I would<br />
like you to stop. Or at least to seriously reconsider your way of<br />
enforcing them.<br />
<br />
AndreaRossato -- Wed Jul 25 2007 19:57 CEST<br />
<br />
==Amendments Proposal==<br />
I think we could use this episode to grow, as a community. I suggest some amendments to these guidelines:<br />
# enforcement: we could add something about guidelines enforcement, referring to the link I [http://c2.com/cgi/wiki?HowToReactToGoodStyleTransgressions posted before]: the user's Talk page should be used instead, and cosmetic edits should be ruled out as a bad practice, incompatible with the wiki philosopy;<br />
# page renaming: we should adopt a very strict policy for page renaming. URI persistence should be the primary goal, so page names can be changed only within a very short period of time after page creation, only for compelling reasons and only with the consent of other users, after discussing it in the talk page;<br />
# wiki structure: I'm not going to make any proposal but I would like you to think about the fact that wiki pages should be all top level, with no (false) hierarchy. This means that using slashes in page name should be considered bad practice.<br />
I hope I will find people willing to discuss these proposals.<br />
Thanks for your kind attention. --AndreaRossato Jul 26 07:59 CEST<br />
:Hi Andrea - First - I have to say I am glad as all get out that you are still taking part in the wiki. I will be more than happy to continue the disucssion of the points above. I am off on vacation for a few days, so I won't add anything more for right now. I would suggest a few things regarding this:<br />
:*Let's move the proposal to the top of the page so that it is the first thing people see. We may even want to group the rest (or some of the rest) as old history.<br />
:*It might be a good idea to advertise this on the haskell mailing list and the haskell-cafe lists. Some people who are interested might not check the latest changes. Previous discussions seemed effective to me because there were multiple points of view.<br />
:--[[User:BrettGiles|BrettGiles]] 01:24, 27 July 2007 (UTC)</div>BrettGileshttps://wiki.haskell.org/index.php?title=HaskellWiki_talk:Guidelines&diff=14692HaskellWiki talk:Guidelines2007-07-25T21:58:49Z<p>BrettGiles: I like the consistency the guidelines give the pages.</p>
<hr />
<div>==Headlines==<br />
<br />
[[User:BrettGiles|Brett]], this is not to offend you. It just expresses my conviction. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]]<br />
<br />
:Not to worry [[User:Wolfgang Jeltsch|Wolfgang]] - I never take offence :) - My thoughts on the usage of level 2 only were primarily due to the size balance, but also I note this is a guideline for the original mediawiki site. Does anyone know why that is? [[User:BrettGiles|BrettGiles]] 22:11, 25 February 2006 (UTC)<br />
<br />
::No idea, but it seems loose to me. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 22:40, 25 February 2006 (UTC)<br />
<br />
:::I did some research on [http://meta.wikimedia.org/wiki/Help_talk:Section metawiki] and this is the reason they start at level 2. ''"So that when a user without CSS, or a text-mode browser, or a screen reader visits, they'll be presented with a page that at least has a logical document flow."'' From what I can tell, by default, the page title is rendered as a '''h1''' element. So are single '''=''' headings. Double '''==''' are '''h2''' and so on. So from that point of view it does make sense to start at two equals. I think the real issue is that the software is slightly broken in not generating an '''h2''' for a single equals sign. So, what do you think? [[User:BrettGiles|BrettGiles]] 22:36, 26 February 2006 (UTC)<br />
<br />
::::I prefer starting with ==, like Wikipedia. &mdash;[[User:Ashley Y|Ashley Y]] 00:52, 2 March 2006 (UTC)<br />
<br />
::::MediaWiki is broken in not creating an '''h2''' element for a headline with single equal signs. So we should work around this brokeness by making our top-level headlines <tt>==</tt> headlines. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 21:22, 8 March 2006 (UTC)<br />
<br />
:::::I've added a respective section to [[HaskellWiki:Guidelines]]. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 21:40, 8 March 2006 (UTC)<br />
<br />
==Page nameing and renaming==<br />
Apparently the last rename I did so offended the author that they quit the wiki. I used to follow the guideline I just added on the main page, but had never got a response before. However, considering the size of the wiki and the number of new users (especially those that seem to not know there are guidelines :), perhaps it is time to re-institute the practice. --[[User:BrettGiles|BrettGiles]] 18:04, 24 July 2007 (UTC)<br />
<br />
==Official guidelines?==<br />
<br />
What makes a guidline an "official" guidline? What's the process? &mdash;[[User:Ashley Y|Ashley Y]] 00:53, 2 March 2006 (UTC)<br />
<br />
:I suspect that a large number of the users / contributors to this site have an academic background. My experience with academia is that some kind of consensus based decision is the most successful at getting the decision adopted. In a community like this wiki, I’m not sure how to get that. We could send out notices on the various mailing lists, we could post notes on the front page and probably other ways as well. Like any consensus decision making it would take a long time. On the other hand, those that support the site could just be autocratic, set the rule and if there is too much flak, change it. <br />
:As to what actually makes an "official" guidline, I think it is up to the '''sysops''' whether we even have such a thing. The word tends to mean that '''sysops''' are required to monitor and fix the site when these are not followed. So, we might not even want to go to official, stay at unofficial and just let the community grow the guidlines (and do the monitoring) as they see fit. Sometimes, a certain level of anarchy works fine.[[User:BrettGiles|BrettGiles]] 16:06, 2 March 2006 (UTC)<br />
::I think that the traditional consensus decision making process is too slow. In addition, not everyone is interested in every guideline question, so it is not sensible to bother everyone with each of these questions. Therefore, it seems to me that it is better to follow your “autocracy approach”. And I also doubt that it is sensible to let some sysops decide about what guidelines are official. At least, this would be a bit contrary to the wiki approach, in my opinion. So I propose that users are allowed to set up guidelines they think of as sensible—possibly after some short discussion—and to declare them as official. If others don't like the guidelines, the guidelines can still be discussed (again) and changed. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 21:22, 8 March 2006 (UTC)<br />
<br />
OK. Everything on the project page should have a consensus. Everything else should be discussed here. I have adjusted the project page accordingly. &mdash;[[User:Ashley Y|Ashley Y]] 06:34, 3 March 2006 (UTC)<br />
:What is the “project page”? -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 21:22, 8 March 2006 (UTC)<br />
::Ah, I understand. It's [[HaskellWiki:Guidelines]]. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 21:40, 8 March 2006 (UTC)<br />
<br />
== Headlines ==<br />
<br />
Each page has a title which is automatically shown near the top of the page (currently centered and in red). So it doesn't make sense to put a single level 1 headline at the top of the page. (At the moment, you will see this on a few pages of this wiki. I suppose this is a legacy which comes from copying content from the old website to this wiki.)<br />
<br />
For top-level structuring, level 1 headlines (the ones denoted by single equals signs in the source) should be used. It is semantically incorrect to use level 2 headlines for this purpose. I note that level 1 headlines are currently rather large and in a font that might not be preferable. However, the solution to this is not to refrain from using level 1 headlines but to change the stylesheet appropriately. ''&mdash;says [[User:Wolfgang Jeltsch]]''<br />
<br />
:Note that is is currently being discussed. Level 1 (single equals) create an <tt>&lt;h1&gt;</tt> heading, which is the same level as the page title. We may (or may not:) switch to the standard of starting at level 2 (double equals) ''&mdash;says [[User:BrettGiles]]''<br />
<br />
:I prefer starting with level 2 as per Wikipedia. I consider the page title to be implicitly level 1 (whether it gets rendered as h1 or not). &mdash;[[User:Ashley Y|Ashley Y]] 06:34, 3 March 2006 (UTC)<br />
<br />
<br />
== Wiki Bug ==<br />
Try giving a Haskell example with the greater than or the less than sign in it. It clashes with the HTML rendering! -- says [[User:Uchchwhash|Pirated Dreams]] 04:22, 17 March 2006 (UTC)<br />
<br />
==What's Wrong With This Guidelines==<br />
I don't know how these guidelines became the official policy of this<br />
wiki, and I cannot find out how some of us decided to become the<br />
housekeepers, or the [http://c2.com/cgi/wiki?WikiGnome WikiGnome]s, of<br />
it.<br />
<br />
Still I've been involved in wiki development and I have some ideas on<br />
how a wiki should work. I tried to discuss it in the<br />
[http://www.haskell.org/pipermail/haskell-cafe/2007-July/029483.html haskell-café mailing list].<br />
<br />
Probably I should do that here too.<br />
<br />
[http://c2.com/cgi/wiki?HowToReactToGoodStyleTransgressions How to react to good style transgression?]<br />
Are these guidelines to be enforced? Aren't enforced guidelines a<br />
contradiction in terms? Sure they are...<br />
<br />
I don't think that cosmetic edits done just to enforce these<br />
guidelines are going to help this wiki on the long run. They piss<br />
newcomers off. And you are pissing off right the newcomers you would<br />
like to keep, the ones who are willing to contribute.<br />
<br />
You could start by reading the new material, and doing some edit to<br />
the content: if you collaborate the wiki way, probably your<br />
suggestions on style issues would be followed.<br />
<br />
Anyway, these are guidelines, or they pretend they are, and so you<br />
must always think about the fact the new paths can be taken.<br />
<br />
Instead what you have been doing, in the last year, is setting some<br />
rules here and reshaping the wiki in the name of those rules.<br />
<br />
===And what is right with these guidelines===<br />
So, when the "new" wiki started, there was quite a bit of discussion here and on the haskell list about what was an appropriate style for the wiki pages, considering that the site is meant to be a resource for new and exsisting Haskell users and as such, were desired to be reasonably consistent in style. These guidelines were the result. A variety of people edit pages to bring them into the stylistic guidelines, but if anyone is not happy with the current set, this seems like a good place to discuss changing them. <br />
<br />
Andrea's link to the "WikiGnome" has some very good pointers about stylistic changes being applied to the edits of ''newcomers'', and an even better one about dropping the argument. So this is my last edit about the subject :) --[[User:BrettGiles|BrettGiles]] 21:58, 25 July 2007 (UTC)<br />
<br />
And that leads me to the second real big issue: page renaming.<br />
<br />
==Why Page Renaming Is BAD==<br />
<br />
Wiki page titles are [http://en.wikipedia.org/wiki/URI URI], and URI<br />
should be persistent over time.<br />
<br />
When you rename a page you are breaking URI persistence. A redirect is<br />
only a work around. A bad work around.<br />
<br />
You did a lot of page renaming lately. By doing so you broke a lot of<br />
URIs.<br />
<br />
You are also breaking the structure of this wiki, by creating a false<br />
hierarchy of pages. In a wiki all pages are top level. Hierarchy and<br />
wikis belong to different worlds.<br />
<br />
I do believe that this guidelines are used in a vary bad way. I would<br />
like you to stop. Or at least to seriously reconsider your way of<br />
enforcing them.<br />
<br />
AndreaRossato -- Wed Jul 25 2007 19:57 CEST</div>BrettGileshttps://wiki.haskell.org/index.php?title=The_Monadic_Way/Part_I&diff=14665The Monadic Way/Part I2007-07-24T22:54:24Z<p>BrettGiles: /* Some output, please! */ links, spelling</p>
<hr />
<div>'''Note: this is the first part of [[The Monadic Way]]'''<br />
==An evaluation of Philip Wadler's "Monads for functional programming"==<br />
<br />
This tutorial is a "translation" of Philip Wadler's [http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf "Monads for functional programming"].<br />
(avail. from [http://homepages.inf.ed.ac.uk/wadler/topics/monads.html here])<br />
<br />
I'm a Haskell newbie trying to grasp such a difficult concept as the<br />
one of Monad and monadic computation.<br />
<br />
While [http://www.cs.utah.edu/~hal/htut/ "Yet Another Haskell Tutorial"] <br />
gave me a good understanding of the [[type]] system when it<br />
comes to monads I find it almost unreadable.<br />
<br />
But I had also Wadler's paper, and started reading it. Well, just<br />
wonderful! It explains how to ''create'' a monad!<br />
<br />
So I decided to "translate it", in order to clarify to myself the<br />
topic. And I'm now sharing this translation ('''not completed yet'')<br />
with the hope it will be useful to someone else.<br />
<br />
Moreover, this is a wiki, so please improve it. Specifically, please<br />
correct my poor English. I'm Italian, after all.<br />
<br />
'''Note: The source of this page can be used as a [[Literate programming|literate Haskell]] file and can be run with [[GHC/GHCi|ghci]] or [[hugs]]: So cut paste change and run (in [[Haskell mode for Emacs |emacs]] for instance) while reading it...'''<br />
<br />
==A simple evaluator==<br />
<br />
Let's start with something simple: suppose we want to implement a new<br />
programming language. We just finished with<br />
[http://swiss.csail.mit.edu/classes/6.001/abelson-sussman-lectures/ Abelson and Sussman's Structure and Interpretation of Computer Programs] <br />
and we want to test what we have learned.<br />
<br />
Our programming language will be very simple: it will just compute the<br />
sum of two terms.<br />
<br />
So we have just one primitive operation (Add) that takes two constants<br />
and calculates their sum.<br />
<br />
Moreover we have just one kind of [[algebraic datatype]]: Con a, which is an Int.<br />
<br />
For instance, something like:<br />
<br />
(Add (Con 5) (Con 6))<br />
<br />
should yield:<br />
<br />
11<br />
<br />
===The basic evaluator===<br />
<br />
We will implement our language with the help of a data [[type]]<br />
[[constructor]] such as:<br />
<br />
<div id="BasicEval"><br />
<haskell><br />
<br />
> module TheMonadicWay where<br />
> data Term = Con Int<br />
> | Add Term Term<br />
> deriving (Show)<br />
<br />
</haskell><br />
<br />
After that we build our interpreter:<br />
<br />
<haskell><br />
<br />
> eval :: Term -> Int<br />
> eval (Con a) = a<br />
> eval (Add a b) = eval a + eval b<br />
<br />
</haskell><br />
<br />
That's it. Just an example:<br />
<br />
*TheMonadicWay> eval (Add (Con 5) (Con 6))<br />
11<br />
*TheMonadicWay><br />
<br />
Very very simple. The evaluator checks if its [[argument]] is of the form <hask>Con Int</hask>. When it is, the [[function]] just returns the <hask>Int</hask>.<br />
<br />
If the argument is not of the form <hask>Con</hask>, but it is of the form <hask>Add Term Term</hask>, it evaluates the first <hask>Term</hask> and sums the result with the result of the evaluation of the second <hask>Term</hask>.<br />
<br />
As you may understand, our evaluator uses some of the powerful<br />
features of Haskell type system. Instead of writing a [[Parsing expressions and statements|parser]] that takes a string (the user input) and transforms that string into an expression to be evaluated, we use the two type constructors defined for our data type Term (Con and Add) to build the expression - such as<br />
(Add (Con 5) (Con 6)) - and to match the expression's elements in our<br />
"eval" function.<br />
<br />
== Some output, please!==<br />
<br />
Now, that's fine, but we'd like to add some features, like providing<br />
some output, to show how the computation was carried out.<br />
<br />
Well, but Haskell is a pure functional language, with no [[side effect]]s,<br />
we were told.<br />
<br />
Now we seem to be wanting to create a side effect of the computation,<br />
its output, and be able to stare at it...<br />
<br />
If we had some global variable to store the output that would be<br />
simple...<br />
<br />
But we can create the output and carry it along the computation,<br />
concatenating it with the old one, and present it at the end of the<br />
evaluation together with the evaluation of the expression given to our<br />
evaluator/interpreter!<br />
<br />
===The basic evaluator with output===<br />
<br />
Simple and neat:<br />
<div id="BasivEvalO"><br />
<haskell><br />
<br />
> type MOut a = (a, Output)<br />
> type Output = String<br />
> <br />
> formatLine :: Term -> Int -> Output<br />
> formatLine t a = "eval (" ++ show t ++ ") <= " ++ show a ++ " - " <br />
> <br />
> evalO :: Term -> MOut Int<br />
> evalO (Con a) = (a, formatLine (Con a) a)<br />
> evalO (Add t u) = ((a + b),(x ++ y ++ formatLine (Add t u) (a + b)))<br />
> where (a, x) = evalO t<br />
> (b, y) = evalO u<br />
<br />
</haskell><br />
<br />
Now we have what we want. But we had to change our evaluator quite a<br />
bit. <br />
<br />
First we added a [[function]], formatLine, that takes an argument of type<br />
Term (the expression to be evaluated), one of type Int (the result of<br />
the evaluation of Term) and gives back an output of type Output (that<br />
is a synonym of String). This is just a helper function to format<br />
the string to output. Not very interesting at all.<br />
<br />
The evaluator itself changed quite a lot! Now it has a different type<br />
signature: it takes an argument of type Term and produces a new type,<br />
we called it MOut, that is actually a compound pair of a variable type<br />
a (an Int in our evaluator) and a type Output, a string.<br />
<br />
So our evaluator, now, will take a Term (the type of the expressions<br />
in our new programming language) and will produce a pair, composed of<br />
the result of the evaluation (an Int) and the Output, a string.<br />
<br />
So far so good. But what's happening inside the evaluator?<br />
<br />
The first part will just return a pair with the number evaluated ("a")<br />
and the output formatted by formatLine.<br />
<br />
The second part does something more complicated: it returns a pair<br />
composed by <br />
1. the result of the evaluation of the right Term summed to the result<br />
of the evaluation of the second Term<br />
2. the output: the concatenation of the output produced by the<br />
evaluation of the right Term, the output produced by the evaluation of<br />
the left Term (each this evaluation returns a pair with the number and<br />
the output), and the formatted output of the evaluation.<br />
<br />
Let's try it:<br />
*TheMonadicWay> evalO (Add (Con 5) (Con 6))<br />
(11,"eval (Con 5) <= 5 - eval (Con 6) <= 6 - eval (Add (Con 5) (Con 6)) <= 11 - ")<br />
*TheMonadicWay><br />
<br />
It works! Let's put the output this way:<br />
eval (Con 5) <= 5 - <br />
eval (Con 6) <= 6 - <br />
eval (Add (Con 5) (Con 6)) <= 11 -<br />
<br />
Great! We are able to produce a side effect of our evaluation and<br />
present it at the end of the computation, after all.<br />
<br />
Let's have a closer look at this expression:<br />
<haskell><br />
<br />
evalO (Add t u) = ((a + b),(x ++ y ++ formatLine (Add t u) (a + b)))<br />
where (a, x) = evalO t<br />
(b, y) = evalO u<br />
<br />
</haskell><br />
<br />
Why all that? The problem is that we need:<br />
* "a" and "b" to calculate their sum (a + b), that will be the first element of the compund pair rapresenting the type (MOut) our evaluator will return <br />
* "x and "y" (the output of each evaluation) to be concatenated with the ourput of formatLine by the expression (x ++ y ++ formatLine(...)): this will be the second element of the compound pair MOut, the string part.<br />
<br />
So we need to separate the pairs produced by "evalO t" and "evalO u".<br />
<br />
We do that within the where clause (remember: evalO now produces a value of type<br />
MOut Int, i.e. a pair of an Int and a String).<br />
<br />
Then we use the single element, "extraded" within the where clause, to<br />
return a new MOut composed by <br />
<br />
((a + b),(x ++ y ++ formatLine (Add t u) (a + b))).<br />
------ -------------------------------------<br />
Int Output = String<br />
<br />
== Let's go monadic==<br />
<br />
Is there a more general way of doing so?<br />
<br />
Let's analyze the evaluator from another perspective. From the type<br />
perspective.<br />
<br />
We solved our problem by creating a new type, a pair of an Int (the<br />
result of the evaluation) and a String (the output of the process of<br />
evaluation).<br />
<br />
The first part of the evaluator does nothing else but creating, from a<br />
value of type Int, an object of type MOut Int (Int,Output). It does so<br />
by creating a pair with that Int and some text produced by formatLine.<br />
<br />
The second part evaluates the two Term(s) and "stores" the values thus<br />
produced in some variables to be use later to compute the output.<br />
<br />
Let's focus on the "stores" action. The correct term should be<br />
"binds".<br />
<br />
Take a function:<br />
<haskell><br />
f x = x + x<br />
</haskell><br />
"x" appears on both sides of the expression. We say that on the right<br />
side "x" is bound to the value of x given on the left side.<br />
<br />
So<br />
<haskell><br />
f 3<br />
</haskell><br />
binds x to 3 for the evaluation of the expression "x + x".<br />
<br />
Our evaluator binds "a" and "x" / "b" and "y" with the evaluation of<br />
"evalO t" and "evalO u" respectively. <br />
<br />
Then "a","b","x" and "y" will be used in the evaluation of<br />
((a+b),(x++y++formatLine)), that will produce a value of type MOut Int:<br />
<br />
<pre><br />
<br />
((a + b),(x ++ y ++ formatLine (Add t u) (a + b))).<br />
------ -------------------------------------<br />
\ / \ /<br />
Int Output = String<br />
---------------------------------<br />
\ /<br />
MOut Int <br />
</pre><br />
<br />
The binding happens in the "where" clause:<br />
<haskell><br />
where (a, x) = evalO t<br />
(b, y) = evalO u<br />
</haskell><br />
<br />
We know that there is an ad hoc operator for binding variables to a<br />
value: lambda, or \.<br />
<br />
Indeed f x = x + x is syntactic sugar for:<br />
<haskell><br />
f = \x -> x + x<br />
</haskell><br />
When we write f 3 we are actually binding "x" to 3 within what's next<br />
"->", that will be used (substituted) for evaluating f 3.<br />
<br />
So we can try to abstract this phenomenon.<br />
<br />
===Monadic evaluator with output===<br />
What we need is a function that takes our composed type MOut Int and a<br />
function in order to produce a new MOut Int, concatenating the<br />
output of the computation of the first with the output of the<br />
computation of the second.<br />
<br />
This is what bindM does:<br />
<br />
<haskell><br />
<br />
> bindM :: MOut a -> (a -> MOut b) -> MOut b<br />
> bindM m f = (b, x ++ y)<br />
> where (a, x) = m<br />
> (b, y) = f a<br />
<br />
</haskell><br />
<br />
It takes:<br />
* "m": the compound type MOut Int carrying the result of an "eval Term",<br />
* a function "f". This function will take the Int ("a") extracted by the evaluation of "m" ((a,x)=m). This function will produce a new pair: a new Int produced by a new evaluation; some new output.<br />
<br />
bindM will return the new Int in pair with the concatenated outputs<br />
resulting from the evaluation of "m" and "f a".<br />
<br />
As you see, we took the binding part out from evalO and put it in this new function.<br />
<br />
So let's write the new version of the evaluator, that we will call evalM_1:<br />
<br />
<haskell><br />
<br />
> evalM_1 :: Term -> MOut Int<br />
> evalM_1 (Con a) = (a, formatLine (Con a) a)<br />
> evalM_1 (Add t u) = bindM (evalM_1 t) (\a -> <br />
> bindM (evalM_1 u) (\b -> <br />
> ((a + b), formatLine (Add t u) (a + b))<br />
> )<br />
> )<br />
<br />
</haskell><br />
<br />
Ugly, isn't it?<br />
<br />
Let's start from the outside:<br />
<br />
<haskell><br />
bindM (evalM_1 u) (\b -> ((a + b), formatLine (Add t u) (a + b)))<br />
</haskell><br />
<br />
bindM takes the result of the evaluation "evalM_1 u", a type Mout Int,<br />
and a function. It will extract the Int from that type and use it to<br />
bind "b".<br />
<br />
So in bindM (evalM_1 u) (\b ->) "b" will be bound to the value<br />
returned by evalM_1 u, and this bound variable will be available in<br />
what comes after "->" as a bound variable (not free).<br />
<br />
Then the outer part (bindM (evalM_1 t) (\a...) will bind "a" to the<br />
value returned "evalM_1 t", the result of the evaluatuion of the first<br />
Term. This value is needed to evaluate "((a+b), formatLine...) and<br />
produce our final MOut Int.<br />
<br />
We can try to explain "bindM" in a different way by using more descriptive names.<br />
<br />
As we have seen, "bindM" extracts the Int part from our type. The Int<br />
part will be used for further computations and the Output part will be<br />
concatenated. As a result we will have a new pair with a new Int and<br />
an accumulated Output.<br />
<br />
The new version of "bindM":<br />
<haskell><br />
<br />
> getIntFromType typeMOut doSomething = (newInt,oldOutput ++ newOutput)<br />
> where (oldInt,oldOutput) = typeMOut<br />
> (newInt,newOutput) = (doSomething oldInt)<br />
<br />
</haskell><br />
<br />
As you can see it does the very same things that "bindM" does: it<br />
takes something of type MOut and a function to perform some<br />
computation with the Int part. <br />
<br />
In the "where" clause, the old Int and the old output<br />
will be extracted from our type MOut (first line of the "where"<br />
clause). <br />
<br />
A new Int and a new output will be extracted from evaluating<br />
(doSomething oldInt) in the second line.<br />
<br />
Our function will return the new Int and the concatenated outputs.<br />
<br />
We do not need to define our doSomething function, because it will be<br />
an anonymous function:<br />
<br />
<haskell><br />
<br />
> evaluator (Con a) = (a, "output-")<br />
> evaluator (Add t u) = <br />
> getIntFromType (evaluator t) <br />
> (\firstInt -> getIntFromType (evaluator u) <br />
> (\secondInt -> ((firstInt + secondInt),("-newoutput"))))<br />
<br />
</haskell><br />
<br />
As you can see we are feeding our "getIntFromType" with the evaluation<br />
of an expression ("evaluator t" and "evaluator u"). The second<br />
argument of "getIntFromType" is an anonymous function that takes the<br />
"oldInt" and does something with it.<br />
<br />
So we have a series of nested anonymous functions. Their arguments<br />
("\firstInt" and "\secondInt") will be used to produce the computation<br />
we need ("(firstInt + secondInt). Moreover "getIntFromType" will take<br />
care of concatenating the outputs.<br />
<br />
This is the result:<br />
<br />
*TheMonadicWay> evaluator (Add (Con 5) (Con 6))<br />
(11,"output-output--newoutput")<br />
*TheMonadicWay> <br />
<br />
Going back to our "bindM", we can now use lambda notation to write our<br />
evaluator in a more convinient way:<br />
<br />
<haskell><br />
<br />
> evalM_2 :: Term -> MOut Int<br />
> evalM_2 (Con a) = (a, formatLine (Con a) a)<br />
> evalM_2 (Add t u) = evalM_2 t `bindM` \a -><br />
> evalM_2 u `bindM` \b -><br />
> ((a + b), (formatLine (Add t u) (a + b)))<br />
<br />
</haskell><br />
<br />
Now, look at the first part:<br />
<br />
<haskell><br />
evalM_2 (Con a) = (a, formatLine (Con a) a)<br />
</haskell><br />
<br />
We could use a more general way of creating some output. <br />
<br />
We can create a function that takes an Int and returns the type MOut<br />
Int. We do that by pairing the received Int with an empty string "".<br />
<br />
This will be a general way of creating an object with type MOut Int starting from an Int.<br />
<br />
Or, more generaly, a function that takes something of a variable type<br />
a, and return an object of type MOut a, a coumpunt object made up of<br />
an element of type a, and one of type String.<br />
<br />
There it is:<br />
<br />
<haskell><br />
<br />
> mkM :: a -> MOut a<br />
> mkM a = (a, "")<br />
<br />
</haskell><br />
<br />
As you can see, this function will just push an Int and an empty<br />
string ("") inside our type MOut.<br />
<br />
Then we need a method of inserting some text in our object of type<br />
MOut. So we will take a string and return it paired with a void<br />
element "()":<br />
<br />
<haskell><br />
<br />
> outPut :: Output -> MOut ()<br />
> outPut x = ((), x)<br />
<br />
</haskell><br />
<br />
Very simple: we have a string "x" (Output) and create a pair with a ()<br />
instead of an Int, and the output.<br />
<br />
You can see this function as one that pushes a string, paired with a<br />
void int, inside our type MOut.<br />
<br />
Now we can rewrite:<br />
<haskell><br />
evalM_2 (Con a) = (a, formatLine (Con a) a)<br />
</haskell><br />
using the bindM function:<br />
<haskell><br />
evalM_2 (Con a) = outPut (formatLine (Con a) a) `bindM` \_ -> mkM a<br />
</haskell><br />
<br />
First we create an object of type MOut with the Int part (). As you<br />
see bindM will not use it ("\_"), but will concatenate the String part<br />
with the result of mkM, which in turn is the empty string "".<br />
<br />
In other words, first we insert the Output part (a string) in our<br />
MOut, and then we insert the Int paired with an empty string: "bindM"<br />
will not use the void int (the anonymous function will not use it's<br />
argument: "\_"), but will take care of concatenating the non empty<br />
string inserted by "outPut" with the empty one inserted by "mkM".<br />
<br />
Let's rewrite the evaluator:<br />
<br />
<haskell><br />
<br />
> evalM_3 :: Term -> MOut Int<br />
> evalM_3 (Con a) = outPut (formatLine (Con a) a) `bindM` \_ -> <br />
> mkM a<br />
> evalM_3 (Add t u) = evalM_3 t `bindM` \a -><br />
> evalM_3 u `bindM` \b -><br />
> outPut (formatLine (Add t u) (a + b)) `bindM` \_ -> <br />
> mkM (a + b)<br />
<br />
</haskell><br />
<br />
Well, this is fine, definetly better then before, anyway.<br />
<br />
Still we use `bindM` \_ -> that binds something we do not use (_). We<br />
could write a function for this specific case, when we concatenate<br />
computations without the need of binding variables for later uses.<br />
Let's call it `combineM`:<br />
<br />
<haskell><br />
<br />
> combineM :: MOut a -> MOut b -> MOut b<br />
> combineM m f = m `bindM` \_ -> f<br />
<br />
</haskell><br />
<br />
This is just something that will allow us to write the evaluator in a<br />
more concise way. <br />
<br />
So the new evaluator:<br />
<br />
<haskell><br />
<br />
> evalM :: Term -> MOut Int<br />
> evalM (Con a) = outPut (formatLine (Con a) a) `combineM` <br />
> mkM a<br />
> evalM (Add t u) = evalM t `bindM` \a -><br />
> evalM u `bindM` \b -><br />
> outPut (formatLine (Add t u) (a + b)) `combineM` <br />
> mkM (a + b)<br />
<br />
</haskell><br />
<br />
Let's put everything together (changing M into MO, so that this file<br />
will be still usable as a Literate Haskell file):<br />
<br />
<haskell><br />
<br />
> type MO a = (a, Out)<br />
> type Out = String<br />
<br />
> mkMO :: a -> MO a<br />
> mkMO a = (a, "")<br />
<br />
> bindMO :: MO a -> (a -> MO b) -> MO b<br />
> bindMO m f = (b, x ++ y)<br />
> where (a, x) = m<br />
> (b, y) = f a<br />
<br />
> combineMO :: MO a -> MO b -> MO b<br />
> combineMO m f = m `bindM` \_ -> f<br />
<br />
> outMO :: Out -> MO ()<br />
> outMO x = ((), x)<br />
<br />
> evalMO :: Term -> MO Int<br />
> evalMO (Con a) = outMO (formatLine (Con a) a) `combineMO`<br />
> mkMO a<br />
> evalMO (Add t u) = evalMO t `bindMO` \a -><br />
> evalMO u `bindMO` \b -><br />
> outMO (formatLine (Add t u) (a + b)) `combineMO` <br />
> mkMO (a + b)<br />
<br />
</haskell><br />
<br />
==What does bind bind?==<br />
<br />
<div id="Bind"><br />
The evaluator looks like:<br />
<haskell><br />
evalM t >>= \a -> evalM u >>= \b -> outPut "something" >>= \_ -> mkM (a +b)<br />
</haskell><br />
where >>= is bindMO, obviously.<br />
<br />
Let's do some substitution, writing the type of their output of each function:<br />
* evalMO t => (a,Out) - where a is Int<br />
* evalMO u => (b,Out) - where b is the same of a, an Int, but with a different value<br />
* outMO Out = ((),Out)<br />
* mkMO (a+b) => ((a+b),Out) - where (a+b) is the same of a and b, but with a different value from either a and b<br />
<br />
<pre><br />
B | (a,Out) >>= \a -> (b,Out) >>= \b -> ((),Out) >>= \_ >>= ((a + b), Out)---\<br />
i | V V V V V V V V ^ ^ ^ ^ |\<br />
n | |__|________^ | | ^ | | | | | | | MOut Int <=> ((a+b), Out)<br />
d |_____|__(++)__|_Out_|__|__(++)__V_Out_|___|___(++)_|_(++)__|___|____|_____|/<br />
i | | |______(b)__|_____|_____(b)____|__(b)__|___|<br />
n | |_________(a)___________|____________|__(a)__|<br />
g | |_____()_____|<br />
<br />
</pre><br />
<br />
Clear, isn't it?<br />
<br />
"bindMO" is just a function that takes care of gluing together, inside<br />
a data type, a sequence of computations!<br />
<br />
== Some sugar, please!==<br />
Now our evaluator has been completely transformed into a monadic<br />
evaluator. That's what it is: a monad.<br />
<br />
We have a function that constructs an object of type MO Int, formed by<br />
a pair: the result of the evaluation and the accumulated<br />
(concatenated) output.<br />
<br />
The process of accumulation and the act of parting the MO Int into its<br />
component is buried into bindMO, now, that can also preserve some<br />
value for later uses.<br />
<br />
So we have:<br />
* MO a type constructor for a type carrying a pair composed by an Int and a String;<br />
* bindMO, that gives a direction to the process of evaluation: it concatenates computations and captures some side effects we created (the direction is given by the changes in the Out part: there's a "before" when Out was something and there's a "later" when Out is something else).<br />
* mkMO lets us create an object of type MO Int starting from an Int.<br />
<br />
As you see this is all we need to create a monad. In other words<br />
monads arise from the type system and the lambda calculus. Everything<br />
else is just syntactic sugar.<br />
<br />
So, let's have a look at that sugar: the famous do-notation!<br />
<br />
===Monadic evaluator with output in do-notation===<br />
<br />
In order to be able to use the "do-notation" we need to define a new<br />
type and make it an instance of the Monad class. To make a new type an<br />
instance of the Monad class we will have to define the two methods of<br />
this class: (>>=) and "return".<br />
<br />
This is not going to be difficult, because we already created these<br />
two methods: "bindM" and "mkM". Now we will have to rewrite them in<br />
order to reflect the fact that we are not going to use a type, for our<br />
evaluator, that is a synonymous of other types, as we did before.<br />
Indeed our MOut was defined with the "type" keyword. Now we will have<br />
to define a "real" new type with either "newtype" or "data". Since we<br />
are not going to need multiple constructors, we will use "newtype".<br />
<br />
<div id="MonadicEvalIO"><br />
<haskell><br />
<br />
> newtype Eval_IO a = Eval_IO (a, O)<br />
> deriving (Show)<br />
> type O = String<br />
<br />
</haskell><br />
<br />
This is our new type: it will have a single type constructor, whose<br />
name is the same of the type name ("Eval_IO"). The type constructor<br />
takes a parameter ("a"), a variable type, and will build a type formed<br />
by a type "a" (an Int in our case) and a String (O is indeed<br />
synonymous of String).<br />
<br />
We now need to define our "bind" function to reflect the fact that we<br />
are now using a "real" type, and, to unpack its content, we need to do<br />
pattern-matching we the type constructor "Eval_IO". Moreover, since we<br />
must return an Eval_IO type, we will use the type constructor also for<br />
building the new type with the new int and the concatenated output.<br />
<br />
For the rest our "bind" function will be identical to the one we<br />
defined before.<br />
<br />
We are going to use very descriptive names:<br />
<br />
<haskell><br />
<br />
> getInt monad doSomething = Eval_IO (newInt,oldOutput ++ newOutput)<br />
> where Eval_IO (oldInt,oldOutput) = monad<br />
> Eval_IO (newInt,newOutput) = (doSomething oldInt)<br />
<br />
</haskell><br />
<br />
As you can see, we are using Eval_IO to build the result of the<br />
computation to be returned by getInt: "Eval_IO (newInt,oldOutput ++<br />
newOutput)". And we are using it to match the internal components of<br />
our type in the "where" clause.<br />
<br />
We also need to create a function that, like mkO, will take an Int and,<br />
using the type constructor "Eval_IO", will create an object of type<br />
Eval_IO with that Int and an empty string:<br />
<br />
<haskell><br />
<br />
> createEval_IO :: a -> Eval_IO a<br />
> createEval_IO int = Eval_IO (int,"")<br />
<br />
</haskell><br />
<br />
And, finally, we need a function that will insert, in our type, a<br />
string and a void ():<br />
<br />
<haskell><br />
<br />
> print_IO :: O -> Eval_IO ()<br />
> print_IO string = Eval_IO ((), string)<br />
<br />
</haskell> <br />
<br />
With these functions we could write our monadic evaluator without the<br />
"do-notation" like this:<br />
<br />
<haskell><br />
<br />
> evalM_4 :: Term -> Eval_IO Int<br />
> evalM_4 (Con a) = createEval_IO a<br />
> evalM_4 (Add t u) = evalM_4 t `getInt` \a -><br />
> evalM_4 u `getInt` \b -><br />
> print_IO (formatLine (Add t u) (a + b)) `getInt` \_ -><br />
> createEval_IO (a + b)<br />
<br />
</haskell><br />
<br />
It is very similar to the previous evaluator, as you can see. The only<br />
differences are related to the fact that we are now using a "real"<br />
type and not a type synonymous: this requires the use of the type<br />
constructor to match the type and its internal part (as we do in the<br />
"where" clause of our "bind" function: "getInt") or to build the type<br />
(as we do in the "bind" function to return the new Int with the<br />
concatenated output).<br />
<br />
Running this evaluator will produce:<br />
<br />
*TheMonadicWay> evalM_4 (Add (Con 6) (Con 12))<br />
Eval_IO (18,"eval (Add (Con 6) (Con 12)) <= 18 - ")<br />
*TheMonadicWay> <br />
<br />
Now we have everything we need to declare our type, Eval_IO, as an<br />
instance of the Monad class:<br />
<haskell><br />
<br />
> instance Monad Eval_IO where<br />
> return a = createEval_IO a<br />
> (>>=) m f = getInt m f<br />
<br />
</haskell><br />
<br />
As you see we are just using our defined functions as methods for our<br />
instance of the Monad class.<br />
<br />
This is all we need to do. Notice that we do not have to define the<br />
"combineM" function, for chaining computation, as we do with "getInt",<br />
without binding variables for later use within the series of nested<br />
anonymous functions (the "doSomething" part) that will form the "do"<br />
block.<br />
<br />
This function comes for free by just defining our type as an instance<br />
of the Monad class. Indeed, if you look at the definition of the Monad<br />
class in the Prelude you see that "combineM", or (>>) is deduced by<br />
the definition of (>>=):<br />
<br />
<haskell><br />
class Monad m where<br />
return :: a -> m a<br />
(>>=) :: m a -> (a -> m b) -> m b<br />
(>>) :: m a -> m b -> m b<br />
fail :: String -> m a<br />
<br />
-- Minimal complete definition: (>>=), return<br />
p >> q = p >>= \ _ -> q<br />
fail s = error s<br />
</haskell><br />
<br />
You can see that the "combineM"" method (or (>>)) is automatically<br />
derived by the "bindMO" (or >>=) method:<br />
<br />
<haskell><br />
p >> q = p >>= \ _ -> q<br />
</haskell><br />
<br />
We can now write our evaluator using the do-notation:<br />
<br />
<haskell><br />
<br />
> eval_IO :: Term -> Eval_IO Int<br />
> eval_IO (Con a) = do print_IO (formatLine (Con a) a)<br />
> return a<br />
> eval_IO (Add t u) = do a <- eval_IO t<br />
> b <- eval_IO u<br />
> print_IO (formatLine (Add t u) (a + b))<br />
> return (a + b)<br />
<br />
</haskell><br />
<br />
As you can see the anonymous functions are gone. Instead we use this:<br />
a <- eval_IO t<br />
<br />
This seems like an assignment, that cannot be possible in Haskell. In<br />
fact it is just the way our anonymous function's arguments is bound<br />
within a do block.<br />
<br />
Even if it does not seem like a series of nested anonymous functions,<br />
this is what actually a do block is.<br />
<br />
Our monad is defined by three elements: <br />
* a type, with its type constructor(s);<br />
* a bind method: it will bind an unwritten anonymous function's argument to the value of the Int part of our type, or more generally, of the variable type "a". It will also create a series of anonymous functions: a line for each function;<br />
* a "return" function, to insert, into out type, a value of type Int, or, more generally, a value of variable type "a".<br />
<br />
Additionally, we need a function to insert a string in our type,<br />
string that the derived "bind" (>>) will concatenate ignoring the void<br />
(), our "print_IO".<br />
<br />
Within a do block we can thus perform only tree kinds of operations:<br />
* a computation that produces a new Int, packed inside our monad's type, to be extracted and bound to a variable (an anonymous function's argument really):<br />
** this operation requires a binding (">>= \varName ->"), translated into "varName <- computation"<br />
** example: a <- eval_IO t<br />
* a computation that inserts a string into our monad, a string to be concatenated, without the need of binding a variable (an anonymous function's argument really):<br />
** this operation does not require a binding: it will be ">>= \_ ->", i.e. ">>", translated into a simple new line<br />
** example: print_IO (formatLine (Add t u) (a + b))<br />
* a computation that inserts an Int into our monad without the need of binding a variable (an anonymous function's argument really):<br />
** this operation is carried out by the <hask>return</hask> method (usually at the end of a do block, useless in the middle)<br />
** example <hask>return (a + b)</hask><br />
<br />
To sum up, within a block, "do" will take care of creating and<br />
nesting, for us, all the needed anonymous functions so that bound<br />
variables will be available for later computations.<br />
<br />
In this way we can emulate a direction of our computation, a "before"<br />
and an "after", even within a pure functional language. And we can use<br />
this possibility to create and accumulate side effects, like output.<br />
<br />
Let's see the evaluator with output in action:<br />
*TheMonadicWay> eval_IO (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <br />
Eval_IO (54,"eval (Con 6) <= 6 - eval (Con 16) <= 16 - eval (Con 20) <= 20 - eval (Con 12) <= 12 - \<br />
eval (Add (Con 20) (Con 12)) <= 32 - eval (Add (Con 16) (Add (Con 20) (Con 12))) <= 48 - \<br />
eval (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <= 54 - ")<br />
*TheMonadicWay> <br />
<br />
Let's format the output part:<br />
eval (Con 6) <= 6 <br />
eval (Con 16) <= 16 <br />
eval (Con 20) <= 20 <br />
eval (Con 12) <= 12 <br />
eval (Add (Con 20) (Con 12)) <= 32 <br />
eval (Add (Con 16) (Add (Con 20) (Con 12))) <= 48 <br />
eval (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <= 54 <br />
<br />
==[[Type]] and [[Newtype]]: What happened to our output?==<br />
<br />
Well, actually something happened to the output. Let's compare the<br />
output of evalMO (the monadic evaluator written without the<br />
do-notation) and eval_IO:<br />
<br />
*TheMonadicWay> evalMO (Con 6)<br />
(6,"eval (Con 6) <= 6 - ")<br />
*TheMonadicWay> eval_IO (Con 6)<br />
Eval_IO (6,"eval (Con 6) <= 6 - ")<br />
*TheMonadicWay> <br />
<br />
They look almost the same, but they are not the same: the output of<br />
eval_IO has the Eval_IO stuff. It must be related to the changes we<br />
had to do to our evaluator in order to use the do-conation, obviously.<br />
<br />
We can now review some of our basic knowledge of Haskell's type<br />
system.<br />
<br />
What's changed? First the type definition. We have now:<br />
<br />
<haskell><br />
newtype Eval_IO a = Eval_IO (a, O)<br />
deriving (Show)<br />
</haskell><br />
<br />
instead of <br />
<br />
<haskell><br />
type MO a = (a, Out)<br />
</haskell><br />
<br />
Now <hask>return a</hask> is the product of the application of the<br />
type constructor Eval_IO to the pair that are going to form our monad.<br />
<br />
"return" takes an Int and inserts it into our monad. It will also<br />
insert an empty String "" that (>>=) or (>>) will then concatenate in<br />
the sequence of computations they glue together.<br />
<br />
The same for (>>=). It will now return something constructed by<br />
Eval_IO: <br />
<br />
* "newInt", the result of the application of "doSomething" to "oldInt" (better, the binding of "oldInt" in "doSomething");<br />
* the concatenation of "oldOutput" (matched by <hask>Eval_IO (oldInt, oldOutput)</hask> with the evaluation of "monad" - "eval_IO t") and "newOutput", (matched by "Eval_IO(newInt,newOutput)" with the evaluation of "(doSomething monad)" - "eval_IO u").<br />
<br />
That is to say: in the "where" clause, we are matching for the<br />
elements paired in a type Eval_IO: this is indeed the type of "monad"<br />
(corresponding to "eval_IO t" in the body of the evaluator) and<br />
"(doSomething monad)" (where "doSomething" correspond to the<br />
evaluation of "eval_IO u" within an anonymous function with \oldInt as<br />
its argument, argument bound to the result of the previous evaluation<br />
of "monad", that is to say "eval_IO t").<br />
<br />
And so, "Eval_IO (oldInt,oldOutput) = monad" means: match "oldInt" and<br />
"oldOutput", paired in a type Eval_IO, and that are produced by the<br />
evaluation of "monad" (that is to say: "eval_IO t"). The same for<br />
Eval_IO (newInt,newOutput): match "newInt" and "newOutput" produced by<br />
the evaluation of "(doSomething monad)".<br />
<br />
So the output of the evaluator is now not simply a pair made of and<br />
Int and a String. It is a specific type (Eval_IO) that happens to<br />
carry a pair of an Int and a String. But, if we want the Int and the<br />
string, we have to extract them from the Eval_IO type, as we do in the<br />
"where" clause: we ''unpack'' our type object (let's call it with its<br />
name: our monad!) and take out the Int and the String to feed the next<br />
function application and the output generation.<br />
<br />
The same to insert something in our monad: if we want to create a pair<br />
of an Int and a String, pair of type Eval_IO, we now have to ''pack''<br />
them together by using our type constructor, feeding it with a pair<br />
composed by and Int and a String. This is what we do with the "return"<br />
method of out monad and with "print_IO" function, where:<br />
* return insert into the monad an Int;<br />
* print_IO insert into the monad a String.<br />
<br />
So, why cannot we use the old <hask>type MO a = (a, Out)</hask> that<br />
did not required all this additional work (apart the need to<br />
specifically define (>>)?<br />
<br />
Type MO is just a synonymous for (a,Out): the two can be substituted<br />
one for the other. That's it.<br />
<br />
We did not have to pack "a" and "Out" together with a type constructor<br />
to have a new type MO.<br />
<br />
As a consequence, we cannot use MO as an instance of Monad, and so, we<br />
cannot use with it the syntactic sugar we needed: the do-notation.<br />
<br />
That is to say: a type created with the "type" keyword cannot be an<br />
instance of a class, and cannot inherits its methods (in our case<br />
(>>=, >> and return). And without those methods the do-notation is not<br />
usable.<br />
<br />
==Errare monadicum est==<br />
<br />
Now that we have a basic understanding of what a monad is, and does,<br />
we will further explore it by making some changes to our evaluator.<br />
<br />
In this section we will se how to handle exceptions in our monadic<br />
evaluator.<br />
<br />
Suppose that we want to stop the execution of our monad if some<br />
conditions occurs. If our evaluator was to compute divisions, instead<br />
of sums, then we would like to stop the evaluator when a division by<br />
zero occurs, possibly producing some output, instead of the result of<br />
the evaluation of the expression, that explains what happened.<br />
<br />
Basic error handling.<br />
<br />
We will do so starting from the beginning once again...<br />
<br />
===The basic evaluator, non monadic, with exception===<br />
<br />
We just take our basic evaluator, without any output, and write a<br />
method to stop execution if a condition occurs: <br />
<br />
<haskell><br />
<br />
> data M a = Raise Exception<br />
> | Return a<br />
> deriving (Show)<br />
> type Exception = String<br />
<br />
</haskell><br />
<br />
Now, our monad is of datatype "M a" which can either be constructed<br />
with the "Raise" constructor, that takes a String (Exception is a<br />
synonymous of String), or by the "Return" constructor, that takes a<br />
variable type ("a"), an Int in our case.<br />
<br />
<haskell><br />
<br />
> evalE :: Term -> M Int<br />
> evalE (Con a) = Return a<br />
<br />
</haskell><br />
<br />
If evalE matches a Con it will construct a type Return with, inside, the content of the Con.<br />
<br />
<haskell><br />
<br />
> evalE (Add a b) = <br />
> case evalE a of<br />
> Raise e -> Raise e<br />
> Return a -><br />
> case evalE b of <br />
> Raise e -> Raise e<br />
> Return b -><br />
> if (a+b) == 42<br />
> then Raise "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else Return (a+b)<br />
<br />
</haskell><br />
<br />
If evalE matches an Add it will check if evaluating the first part<br />
produces a "Raise" or a "Return": in the first case it will return a<br />
"Raise" whose content is the same received. <br />
<br />
If instead the evaluation produces a value of a type matched by<br />
"Return", the evaluator will evaluate the second term of Add.<br />
<br />
If this returns a "Raise", a "Raise" will be returned all the way up<br />
the recursion, otherwise the evaluator will check whether a condition<br />
for raising a "Raise" exists. If not, it will return a "Return" with<br />
the sum inside.<br />
<br />
Test it with:<br />
<br />
evalE (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2)))<br />
<br />
<br />
===The basic evaluator, monadic, with exceptions===<br />
<br />
In order to produce a monadic version of the previous evaluator, the<br />
one that raises exceptions, we just need to abstract out from the<br />
evaluator all that case analysis.<br />
<br />
<haskell><br />
<br />
> data M1 a = Except Exception<br />
> | Ok {showM :: a }<br />
> deriving (Show)<br />
<br />
</haskell><br />
<br />
The data type didn't change at all. Well, we changed the name of the<br />
Return type constructor (now Ok) so that this constructor can coexist<br />
with the previous one in the same Literate Haskell file.<br />
<br />
<div id="MonadicEvalE"><br />
<haskell><br />
<br />
> instance Monad M1 where<br />
> return a = Ok a<br />
> m >>= f = case m of<br />
> Except e -> Except e<br />
> Ok a -> f a<br />
<br />
</haskell><br />
<br />
Binding operations are now very easy. Basically we check:<br />
* if the result of the evaluation of "m" produces an exception (first match: Except e ->...), in which case we return its content by constructing our M1 Int with the "Raise" constructor".<br />
* if the result of the evaluation of "m" is matched with the "Ok" constructor, we get its content and use it to bind the argument of "f" to its value.<br />
<br />
<hask>return a</hask> will just use the Ok type constructor for<br />
inserting "a" (in our case an Int) into M1 Int, the type of our monad.<br />
<br />
<haskell><br />
<br />
> raise :: Exception -> M1 a<br />
> raise e = Except e<br />
<br />
</haskell><br />
<br />
This is just a helper function to construct our "M1 a" type with the<br />
Raise constructor. It takes a string and returns a type (M1 a) to be<br />
matched with the "Raise" constructor.<br />
<br />
<haskell><br />
<br />
> eval_ME :: Term -> M1 Int<br />
> eval_ME (Con a) = do return a<br />
> eval_ME (Add t u) = do a <- eval_ME t<br />
> b <- eval_ME u<br />
> if (a+b) == 42<br />
> then raise "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
</haskell><br />
<br />
The evaluator itself is very simple. We bind "a" with the result of<br />
"eval_ME t", "b" with the result of "eval_ME u", and we check for a<br />
condition: <br />
* if the condition is met we raise an exception, that is to say: we return a value constructed with the "Raise" constructor. This value will be matched by ">>=" in the next recursion. And >>= will just return it all the way up the recursion.<br />
* if the condition is not met, we return a value constructed with the "Return" type constructor and go on with the recursion.<br />
<br />
Run with:<br />
<br />
eval_ME (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2)))<br />
<br />
It is noteworthy the fact that in our datatype definition we used a<br />
label field with a label selector (we called it showM), even though it<br />
was not used in our code. We will use this methodology later on.<br />
<br />
So, just to refresh your memory:<br />
<br />
<haskell><br />
<br />
> data Person = Person {name :: String,<br />
> age :: Int,<br />
> hobby :: String<br />
> } deriving (Show)<br />
<br />
> andreaRossato = Person "Andrea" 37 "Haskell The Monadic Way"<br />
> personName (Person a b c) = a<br />
<br />
</haskell><br />
<br />
will produce:<br />
*TheMonadicWay> andreaRossato<br />
Person {name = "Andrea", age = 37, hobby = "Haskell The Monadic Way"}<br />
*TheMonadicWay> personName andreaRossato<br />
"Andrea"<br />
*TheMonadicWay> name andreaRossato<br />
"Andrea"<br />
*TheMonadicWay> age andreaRossato<br />
37<br />
*TheMonadicWay> hobby andreaRossato<br />
"Haskell The Monadic Way"<br />
*TheMonadicWay> <br />
<br />
<br />
===Monadic evaluator with output and exceptions===<br />
<br />
We will now try to combine the [[The Monadic Way/Part I#MonadicEvalIO|output-producing monadic evaluator]] <br />
with [[The Monadic Way/Part I#MonadicEvalE| exception producing one]].<br />
<br />
<br />
<haskell><br />
<br />
> data M2 a = Ex Exception<br />
> | Done {unpack :: (a,O) }<br />
> deriving (Show)<br />
<br />
</haskell><br />
<br />
Now we need a [[algebraic datatype]] with two [[constructor]]s: one to produce a value type "M2 a" using "Ex String" and one for value type "M2 a" (Int in<br />
this case) using "Done a".<br />
<br />
'''Note''' that we changed the name of the exception type constructor<br />
from "Raise" to "Ex" just to make the two coexist in the same [[Literate programming|literate Haskell]] file.<br />
<br />
The constructor "Done a" is defined with a label selector: <hask>Done {unpack :: (a,O)}</hask> <br />
and is equivalent to <hask>Done (a,O)</hask>. <br />
<br />
The only difference is that, this way, we are also defining a method<br />
to retrieve the pair (a,O) (in our case "O" is a synonymous for<br />
String, whereas "a" is a variable type) from an object of type "Done<br />
a".<br />
<br />
<haskell><br />
<br />
> instance Monad M2 where<br />
> return a = Done (a, "")<br />
> m >>= f = case m of<br />
> Ex e -> Ex e<br />
> Done (a, x) -> case (f a) of<br />
> Ex e1 -> Ex e1<br />
> Done (b, y) -> Done (b, x ++ y)<br />
<br />
</haskell><br />
<br />
Now our binding operations gets more complicated by the fact that we<br />
have to concatenate the output, as we did before, '''and''' check for<br />
exceptions.<br />
<br />
It is not possible to do has we did in the [[The Monadic Way/Part I#MonadicEvalE| exception producing evaluator]], <br />
where we could check just for "m" (remember the "m" in the first run<br />
stands for "eval t").<br />
<br />
Since at the end we must return the output produced by the evaluation<br />
of "m" ''concatenated'' with the output produced by the evaluation of<br />
"f a" (where "a" is returned by "m", paired with "x" by "Done"), now<br />
we must check if we '''do have''' an output from "f a" produced by<br />
"Done".<br />
<br />
Indeed, now, "f a" can also produce a value constructed by "Ex", and<br />
this value does not contain the pair as the value produced by "Done".<br />
<br />
So, we evaluate "m": <br />
* if we match a value produced by type constructor "Ex" we return a value produced by type constructor "Ex" whose content is the one we extracted in the matching;<br />
* if we match a value produced by "Done" we match the pair it carries "(a,x)" and we analyze what "f a" returns:<br />
** if "f a" returns a value produced by "Ex" we extract the exception and we return it, constructing a value with "Ex"<br />
** if "f a" returns a value produced by "Done" we return "b" and the concatenated "x" and "y". <br />
<br />
And now the evaluator:<br />
<br />
<haskell><br />
<br />
> raise_IOE :: Exception -> M2 a<br />
> raise_IOE e = Ex e<br />
<br />
</haskell><br />
<br />
This is the [[function]] to insert an exception in our monad (M2): We take<br />
a String and produce a value applying the type constructor for exception "Ex" to its value.<br />
<br />
<haskell><br />
<br />
> print_IOE :: O -> M2 ()<br />
> print_IOE x = Done ((), x)<br />
<br />
</haskell><br />
<br />
The function to produce output is the very same of the one of the [[The Monadic Way/Part I#MonadicEvalIO|output-producing monadic evaluator]].<br />
<br />
<haskell><br />
<br />
> eval_IOE :: Term -> M2 Int<br />
> eval_IOE (Con a) = do print_IOE (formatLine (Con a) a)<br />
> return a<br />
> eval_IOE (Add t u) = do a <- eval_IOE t<br />
> b <- eval_IOE u<br />
> let out = formatLine (Add t u) (a + b)<br />
> print_IOE out<br />
> if (a+b) == 42<br />
> then raise_IOE $ out ++ "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
</haskell><br />
<br />
The evaluator procedure did not change very much from the one of the [[The Monadic Way/Part I#MonadicEvalIO|output-producing monadic evaluator]].<br />
<br />
We just added the case analysis to see if the condition for raising an exception is met.<br />
<br />
Running with<br />
<br />
eval_IOE (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2)))<br />
<br />
will produce <br />
<br />
Ex "eval (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2))) <= 42 - <br />
The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
<br />
Look at the <hask>let</hask> clause within the do-notation. We do not<br />
need to use the "let ... in" construction: since all [[bound variable]]s<br />
remain bound within a <hask>do</hask> procedure (see [[The Monadic Way/Part I#Bind|here]]), <br />
we do not need the "in" to specify "where" the variable "out" will be bound in!<br />
<br />
==We need a state==<br />
<br />
We will keep on adding complexity to our monadic evaluator and this<br />
time we will add a counter. We just want to count the number of<br />
iterations (the number of times "eval" will be called) needed to<br />
evaluate the expression.<br />
<br />
===The basic evaluator, non monadic, with a counter===<br />
<br />
As before we will start by adding this feature to our [[The Monadic Way Part I#BasicEval|basic evaluator]]. <br />
<br />
A method to count the number of iterations, since the lack of<br />
assignment and destructive updates (such as for i=0;i<10;i++;),<br />
is to add an argument to our function, the initial state, number that<br />
in each call of the function will be increased and passed to the next<br />
function call.<br />
<br />
And so, very simply:<br />
<br />
<haskell><br />
<br />
> -- non monadic<br />
> type St a = State -> (a, State)<br />
> type State = Int<br />
> evalNMS :: Term -> St Int<br />
> evalNMS (Con a) x = (a, x + 1)<br />
> evalNMS (Add t u) x = let (a, y) = evalNMS t x in<br />
> let (b, z) = evalNMS u y in<br />
> (a + b, z +1)<br />
<br />
</haskell><br />
<br />
Now evalNMS takes two arguments: the expression of type Term and an<br />
State (which is a synonymous for Int), and will produce a pair<br />
(a,State), that is to say a pair with a variable type "a" and an Int.<br />
<br />
The operations in the evaluator are very similar to the non monadic [[The Monadic Way Part I#BasivEvalO|output producing evaluator]].<br />
<br />
We are now using the "let ... in" clause, instead of the "where", and we are increasing the counter "z" the comes from the evaluation of the second term, but the basic operation are the same:<br />
* we evaluate "evalNMS t x" where "x" is the initial state, and we match and bind the result in "let (a, y) ... in"<br />
* we evaluate "evalNMS u y", where "y" was bound to the value returned by the previous evaluation, and we match and bind the result in "let (b, z) ... in"<br />
* we return a pair formed by the sum of the result (a+b) and the state z increased by 1. <br />
<br />
Let's try it:<br />
<br />
*TheMonadicWay> evalNMS (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2))) 0<br />
(42,7)<br />
*TheMonadicWay> <br />
<br />
As you see we must pass to "evalNMS"the initial state of our counter: 0.<br />
<br />
Look at the type signature of the function "evalNMS":<br />
<haskell><br />
evalNMS :: Term -> St Int<br />
</haskell><br />
<br />
From this signature you could argue that our function takes only<br />
'''one''' argument. But since our type St is defined with the "type"<br />
keyword, St can be substituted with what comes after the "=" sign. So,<br />
the real type signature of our function is:<br />
<br />
<haskell><br />
evalNMS :: Term -> State -> (Int,State)<br />
</haskell><br />
<br />
<div if="typeNewtype"><br />
Just to refresh your memory:<br />
<br />
<haskell><br />
<br />
> type IamAfunction a = (a -> a)<br />
> newtype IamNotAfunction a = NF (a -> a)<br />
> newtype IamNotAfunctionButYouCanUnPackAndRunMe a = F { unpackAndRun :: (a -> a) }<br />
<br />
> a = \x -> x * x<br />
<br />
> a1 :: IamAfunction Integer<br />
> a1 = a<br />
<br />
> a2 :: IamNotAfunction Integer<br />
> a2 = NF a<br />
<br />
> a3 :: IamNotAfunctionButYouCanUnPackAndRunMe Integer<br />
> a3 = F a<br />
<br />
</haskell><br />
<br />
<br />
*TheMonadicWay> a 4<br />
16<br />
*TheMonadicWay> a1 4<br />
16<br />
*TheMonadicWay> a2 4<br />
<br />
<interactive>:1:0:<br />
The function `a2' is applied to one arguments,<br />
but its type `IamNotAfunction Int' has only 0<br />
In the definition of `it': it = a2 4<br />
*TheMonadicWay> a3 4<br />
<br />
<interactive>:1:0:<br />
The function `a3' is applied to one arguments,<br />
but its type `IamNotAfunctionButYouCanUnPackAndRunMe Int' has only 0<br />
In the definition of `it': it = a3 4<br />
*TheMonadicWay> unpackAndRun a3 4<br />
16<br />
*TheMonadicWay><br />
<br />
This means that "a1" is a partial application hidden by a type<br />
synonymous. <br />
<br />
"a2" and "a3" are not function types. They are types that<br />
have a functional value. <br />
<br />
Moreover, since we defined the type constructor of type<br />
"IamNotAfunctionButYouCanUnPackAndRunMe", F, with a label field, in<br />
that label field we defined a method (a label selector) to "extract"<br />
the function from the type "IamNotAfunctionButYouCanUnPackAndRunMe",<br />
and run it:<br />
<br />
<haskell><br />
unpackAndRun a3 4<br />
</haskell><br />
<br />
And what about "a2"? Is it lost forever?<br />
<br />
Obviously not! We need to write a function that unpacks a type<br />
"IamNotAfunction", using its type constructor NF to match the internal<br />
function:<br />
<br />
<haskell><br />
<br />
> unpackNF :: IamNotAfunction a -> a -> a<br />
> unpackNF (NF f) = f<br />
<br />
</haskell><br />
<br />
and run:<br />
<br />
*TheMonadicWay> unpackNF a2 4<br />
16<br />
*TheMonadicWay> <br />
<br />
As you see, "unpackNF" definition is a partial application: we specify<br />
one argument to get a function that gets another argument.<br />
<br />
A label selector does the same thing.<br />
<br />
Later we will see the importance of this distinction, quite obvious<br />
for haskell gurus, but not for us. Till now.<br />
<br />
===The evaluator, monadic, with a counter===<br />
<br />
We will now rewrite our basic evaluator with the counter in<br />
do-notation.<br />
<br />
As we have seen, in order to do so we need:<br />
* a new type that we must declare as an instance of the Monad class;<br />
* a function for binding method (>>=) and a function for the "return" method, for the instance declaration; <br />
<br />
Now our type will be holding a function that will take the initial<br />
state 0 as we did before.<br />
<br />
In order to simplify the process of unpacking the monad each time to<br />
get the function, we will use a label sector:<br />
<br />
<haskell><br />
<br />
> newtype MS a = MS { unpackMSandRun :: (State -> (a, State)) }<br />
<br />
</haskell><br />
<br />
This is it: MS will be our type constructor for matching and for<br />
building our monad. "unpackMSandRun" will be the method to get the<br />
function out of the monad to feed it with the initial state of the<br />
counter, 0, to get our result.<br />
<br />
Then we need the "return" function that, as we have seen does nothing<br />
but inserting into our monad an Integer:<br />
<br />
<haskell><br />
<br />
> mkMS :: a -> MS a<br />
> mkMS int = MS (\x -> (int, x))<br />
<br />
</haskell><br />
<br />
"mkMS" will just take an Integer "a" and apply the MS type constructor<br />
to our anonymous function that takes an initial state and produces the<br />
final state "x" and the integer "a".<br />
<br />
In other words, we are just creating our monad with inside an Integer.<br />
<br />
Our binding function will be a bit more complicated then before. We<br />
must create a type that holds an anonymous function with elements to<br />
be extracted from our type and passed to the anonymous function that<br />
comes next:<br />
<br />
<haskell><br />
<br />
> bindMS :: MS a -> (a -> MS b) -> MS b<br />
> bindMS monad doNext = MS $ \initialState -> <br />
> let (oldInt, oldState) = unpackMSandRun monad initialState in<br />
> let (newInt, newState) = unpackMSandRun (doNext oldInt) oldState in<br />
> (newInt,newState)<br />
<br />
</haskell><br />
<br />
So, we are creating an anonymous function that will take an initial<br />
state, 0, and return a "newInt" and "newState". <br />
<br />
To do that we need to unpack and run our "monad" against the<br />
initialState in order to get the "oldInt" and the "oldState".<br />
<br />
The "oldInt" will be passed to the "doNext" function (the next<br />
anonymous function in our do block) together with the "oldState" to<br />
get the "newInt" and the "newState".<br />
<br />
We can now declare our type "MS" as an instance of the Monad class:<br />
<haskell><br />
<br />
> instance Monad MS where<br />
> return a = mkMS a<br />
> (>>=) m f = bindMS m f<br />
<br />
</haskell><br />
<br />
We now need a function to increase the counter in our monad from<br />
within a do block:<br />
<br />
<haskell><br />
<br />
> incState :: MS ()<br />
> incState = MS (\s -> ((), s + 1))<br />
<br />
</haskell><br />
<br />
This is easier then it looks like. We use the type constructor MS to<br />
create a function that takes a state an returns a void integer ()<br />
paired with the state increased by one. We do not need any binding,<br />
since we are just modifying the state, an integer, and, in our do<br />
block, we will insert this function before a new line, so that the non<br />
binding ">>" operator will be applied.<br />
<br />
And now the evaluator:<br />
<br />
<haskell><br />
<br />
> evalMS :: Term -> MS Int<br />
> evalMS (Con a) = do incState<br />
> mkMS a<br />
> evalMS (Add t u) = do a <- evalMS t<br />
> b <- evalMS u<br />
> incState <br />
> return (a + b)<br />
<br />
</haskell><br />
<br />
Very easy: we just added the "incState" function before returning the<br />
sum of the evaluation of the Terms of our expression.<br />
<br />
Let's try it:<br />
<br />
*TheMonadicWay> unpackMSandRun (evalMS (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12))))) 0<br />
(54,7)<br />
*TheMonadicWay> <br />
<br />
As you can see, adding a counter makes our binding operations a bit<br />
more complicated by the fact that we have an anonymous function within<br />
our monad. This means that we must recreate that anonymous function in<br />
each step of our do block. This makes "incState" and, as we are going<br />
to see in the next paragraph, the function to produce output a bit<br />
more complicated. Anyway we can handle this complexity quite well, for<br />
now.<br />
<br />
===The monadic evaluator with output and counter in do-notation===<br />
<br />
Adding output to our evaluator is now quite easy. It's just a matter<br />
of adding a field to our type, where we are going to accumulate the<br />
output, and take care of extracting it in our bind function to<br />
concatenate the old one with the new one.<br />
<br />
<haskell><br />
<br />
> newtype Eval_SIO a = Eval_SIO { unPackMSIOandRun :: State -> (a, State, Output) }<br />
<br />
</haskell><br />
<br />
Now our monad contains an anonymous function that takes the initial<br />
state, 0, and will produce the final Integer, the final state and the<br />
concatenated output.<br />
<br />
So, this is bind:<br />
<br />
<haskell><br />
<br />
> bindMSIO monad doNext = <br />
> Eval_SIO (\initialState -><br />
> let (oldInt, oldState, oldOutput) = unPackMSIOandRun monad initialState in<br />
> let (newInt, newState, newOutput) = unPackMSIOandRun (doNext oldInt) oldState in<br />
> (newInt, newState, oldOutput ++ newOutput))<br />
<br />
</haskell><br />
<br />
And this is our "return":<br />
<haskell><br />
<br />
> mkMSIO int = Eval_SIO (\s -> (int, s, ""))<br />
<br />
</haskell><br />
<br />
Now we can declare our type, "Eval_SIO", as an instance of the Monad class:<br />
<br />
<haskell><br />
<br />
> instance Monad Eval_SIO where<br />
> return a = mkMSIO a<br />
> (>>=) m f = bindMSIO m f<br />
<br />
</haskell><br />
<br />
Now, the function to increment the counter will also insert an empty<br />
string "" in our monad: "bind" will take care of concatenating it with<br />
the old output:<br />
<br />
<haskell><br />
<br />
> incSIOstate :: Eval_SIO () <br />
> incSIOstate = Eval_SIO (\s -> ((), s + 1, ""))<br />
<br />
</haskell><br />
<br />
The function to insert some new output will just insert a string into<br />
our monad, together with a void Integer (). Since no binding will<br />
occur (>> will be applied), the () will not be taken into<br />
consideration within the anonymous functions automatically created for<br />
us within the do block:<br />
<br />
<haskell><br />
<br />
> print_SIO :: Output -> Eval_SIO ()<br />
> print_SIO x = Eval_SIO (\s -> ((),s, x))<br />
<br />
</haskell><br />
<br />
And now the evaluator, that puts everything together. As you can see<br />
it did not change too much from the previous versions:<br />
<br />
<haskell><br />
<br />
> eval_SIO :: Term -> Eval_SIO Int<br />
> eval_SIO (Con a) = do incSIOstate<br />
> print_SIO (formatLine (Con a) a)<br />
> return a<br />
> eval_SIO (Add t u) = do a <- eval_SIO t<br />
> b <- eval_SIO u<br />
> incSIOstate<br />
> print_SIO (formatLine (Add t u) (a + b))<br />
> return (a + b)<br />
<br />
</haskell><br />
<br />
Running it will require unpacking the monad and feeding it with the initial state 0:<br />
<br />
unPackMSIOandRun (eval_SIO (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12))))) 0<br />
*TheMonadicWay> unPackMSIOandRun (eval_SIO (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12))))) 0<br />
(54,7,"eval (Con 6) <= 6 - eval (Con 16) <= 16 - <br />
eval (Con 20) <= 20 - <br />
eval (Con 12) <= 12 - <br />
eval (Add (Con 20) (Con 12)) <= 32 - <br />
eval (Add (Con 16) (Add (Con 20) (Con 12))) <= 48 - <br />
eval (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <= 54 - ")<br />
*TheMonadicWay> <br />
<br />
(I formatted the output).<br />
<br />
<br />
==If there's a state we need some discipline: Dealing with complexity==<br />
<br />
'''(Text to be done yet: just a summary)'''<br />
<br />
In order to increase the complexity of our monad now we will try to<br />
mix State (counter), Exceptions and Output.<br />
<br />
This is an email [http://www.haskell.org/pipermail/haskell-cafe/2006-August/017672.html I send to the haskell-cafe mailing list]:<br />
<br />
<pre><br />
Now I'm trying to create a statefull evaluator, with output and<br />
exception, but I'm facing a problem I seem not to be able to<br />
conceptually solve.<br />
<br />
Take the code below.<br />
Now, in order to get it run (and try to debug) the Eval_SOI type has a<br />
Raise constructor that produces the same type of SOIE. Suppose instead it<br />
should be constructing something like Raise "something". <br />
Moreover, I wrote a second version of >>=, commented out.<br />
This is just to help me illustrate to problem I'm facing.<br />
<br />
Now, >>= is suppose to return Raise if "m" is matched against Raise<br />
(second version commented out).<br />
If "m" matches SOIE it must return a SOIE only if "f a" does not<br />
returns a Raise (output must be concatenated).<br />
<br />
I seem not to be able to find a way out. Moreover, I cannot understand<br />
if a way out can be possibly found. Something suggests me it could be<br />
related to that Raise "something".<br />
But my feeling is that functional programming could be something out<br />
of the reach of my mind... by the way, I teach Law, so perhaps you'll<br />
forgive me...;-)<br />
<br />
If you can help me to understand this problem all I can promise is<br />
that I'll mention your help in the tutorial I'm trying to write on<br />
"the monadic way"... that seems to lead me nowhere.<br />
<br />
Thanks for your kind attention.<br />
<br />
Andrea<br />
</pre><br />
<br />
This was the code:<br />
<br />
<haskell><br />
data Eval_SOI a = Raise { unPackMSOIandRun :: State -> (a, State, Output) }<br />
| SOIE { unPackMSOIandRun :: State -> (a, State, Output) }<br />
<br />
instance Monad Eval_SOI where<br />
return a = SOIE (\s -> (a, s, ""))<br />
m >>= f = SOIE (\x -><br />
let (a, y, s1) = unPackMSOIandRun m x in<br />
case f a of<br />
SOIE nextRun -> let (b, z, s2) = nextRun y in <br />
(b, z, s1 ++ s2)<br />
Raise e1 -> e1 y --only this happens<br />
<br />
)<br />
-- (>>=) m f = case m of<br />
-- Raise e -> error "ciao" -- why this is not going to happen?<br />
-- SOIE a -> SOIE (\x -><br />
-- let (a, y, s1) = unPackMSOIandRun m x in<br />
-- let (b, z, s2) = unPackMSOIandRun (f a) y in <br />
-- (b, z, s1 ++ s2)) <br />
<br />
<br />
incSOIstate :: Eval_SOI ()<br />
incSOIstate = SOIE (\s -> ((), s + 1, ""))<br />
<br />
print_SOI :: Output -> Eval_SOI ()<br />
print_SOI x = SOIE (\s -> ((),s, x))<br />
<br />
raise x e = Raise (\s -> (x,s,e))<br />
<br />
eval_SOI :: Term -> Eval_SOI Int<br />
eval_SOI (Con a) = do incSOIstate<br />
print_SOI (formatLine (Con a) a)<br />
return a<br />
eval_SOI (Add t u) = do a <- eval_SOI t<br />
b <- eval_SOI u<br />
incSOIstate<br />
print_SOI (formatLine (Add t u) (a + b))<br />
if (a + b) == 42 <br />
then raise (a+b) " = The Ultimate Answer!!"<br />
else return (a + b)<br />
<br />
runEval exp = case eval_SOI exp of<br />
Raise a -> a 0<br />
SOIE p -> let (result, state, output) = p 0 in<br />
(result,state,output)<br />
<br />
<br />
<br />
--runEval (Add (Con 10) (Add (Con 28) (Add (Con 40) (Con 2))))<br />
</haskell><br />
<br />
This code will produce <br />
<br />
eval (Con 10) <= 10 -<br />
eval (Con 28) <= 28 -<br />
eval (Con 40) <= 40 -<br />
eval (Con 2) <= 2 - = The Ultimate Answer!!<br />
eval (Add (Con 28) (Add (Con 40) (Con 2))) <= 70 -<br />
eval (Add (Con 10) (Add (Con 28) (Add (Con 40) (Con 2)))) <= 80 -<br />
<br />
The exception appears in the output, but executioon is not stopped.<br />
<br />
===Monadic evaluator with output, counter and exception, in do-notation===<br />
<br />
Brian Hulley [http://www.haskell.org/pipermail/haskell-cafe/2006-August/017680.html came up with this solution]:<br />
<br />
<haskell><br />
<br />
> -- thanks to Brian Hulley<br />
> data Result a<br />
> = Good a State Output<br />
> | Bad State Output Exception<br />
> deriving Show<br />
<br />
> newtype Eval_SIOE a = SIOE {runSIOE :: State -> Result a}<br />
<br />
> instance Monad Eval_SIOE where<br />
> return a = SIOE (\s -> Good a s "")<br />
> m >>= f = SIOE $ \x -><br />
> case runSIOE m x of<br />
> Good a y o1 -><br />
> case runSIOE (f a) y of<br />
> Good b z o2 -> Good b z (o1 ++ o2)<br />
> Bad z o2 e -> Bad z (o1 ++ o2) e<br />
> Bad z o2 e -> Bad z o2 e<br />
<br />
> raise_SIOE e = SIOE (\s -> Bad s "" e)<br />
<br />
> incSIOEstate :: Eval_SIOE ()<br />
> incSIOEstate = SIOE (\s -> Good () (s + 1) "")<br />
<br />
> print_SIOE :: Output -> Eval_SIOE ()<br />
> print_SIOE x = SIOE (\s -> Good () s x)<br />
<br />
<br />
> eval_SIOE :: Term -> Eval_SIOE Int<br />
> eval_SIOE (Con a) = do incSIOEstate<br />
> print_SIOE (formatLine (Con a) a)<br />
> return a<br />
> eval_SIOE (Add t u) = do a <- eval_SIOE t<br />
> b <- eval_SIOE u<br />
> incSIOEstate<br />
> let out = formatLine (Add t u) (a + b)<br />
> print_SIOE out<br />
> if (a+b) == 42<br />
> then raise_SIOE $ out ++ "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
> runEval exp = case runSIOE (eval_SIOE exp) 0 of<br />
> Bad s o e -> "Error at iteration n. " ++ show s ++ <br />
> " - Output stack = " ++ o ++ <br />
> " - Exception = " ++ e<br />
> Good a s o -> "Result = " ++ show a ++ <br />
> " - Iterations = " ++ show s ++ " - Output = " ++ o<br />
<br />
</haskell><br />
<br />
Run with runEval (Add (Con 18) (Add (Con 12) (Add (Con 10) (Con 2))))<br />
<br />
==Suggested readings==<br />
<br />
:Cale Gibbard, [[Monads as containers]]<br />
:Jeff Newbern, [http://haskell.org/all_about_monads/html/contmonad.html All About Monads]<br />
:[[IO inside]]<br />
:[http://sigfpe.blogspot.com/2006/08/you-could-have-invented-monads-and.html You Could Have Invented Monads! (And Maybe You Already Have.) by sigfpe]<br />
<br />
<br />
==Acknowledgments==<br />
<br />
Thanks to Neil Mitchell, Daniel Fisher, Bulat Ziganzhin, Brian Hulley<br />
and Udo Stenzel for the invaluable help they gave, in the<br />
[http://www.haskell.org/mailman/listinfo/haskell-cafe haskell-cafe mailing list], <br />
in understanding this topic.<br />
<br />
I couldn't do it without their help.<br />
<br />
Obviously errors are totally mine. But this is a wiki so, please,<br />
correct them!<br />
<br />
- [[User:AndreaRossato|Andrea Rossato]]<br />
<br />
[[Category:Tutorials]]<br />
[[Category:Monad]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=The_Monadic_Way/Part_I&diff=14664The Monadic Way/Part I2007-07-24T22:51:42Z<p>BrettGiles: /* A simple evaluator */ links</p>
<hr />
<div>'''Note: this is the first part of [[The Monadic Way]]'''<br />
==An evaluation of Philip Wadler's "Monads for functional programming"==<br />
<br />
This tutorial is a "translation" of Philip Wadler's [http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf "Monads for functional programming"].<br />
(avail. from [http://homepages.inf.ed.ac.uk/wadler/topics/monads.html here])<br />
<br />
I'm a Haskell newbie trying to grasp such a difficult concept as the<br />
one of Monad and monadic computation.<br />
<br />
While [http://www.cs.utah.edu/~hal/htut/ "Yet Another Haskell Tutorial"] <br />
gave me a good understanding of the [[type]] system when it<br />
comes to monads I find it almost unreadable.<br />
<br />
But I had also Wadler's paper, and started reading it. Well, just<br />
wonderful! It explains how to ''create'' a monad!<br />
<br />
So I decided to "translate it", in order to clarify to myself the<br />
topic. And I'm now sharing this translation ('''not completed yet'')<br />
with the hope it will be useful to someone else.<br />
<br />
Moreover, this is a wiki, so please improve it. Specifically, please<br />
correct my poor English. I'm Italian, after all.<br />
<br />
'''Note: The source of this page can be used as a [[Literate programming|literate Haskell]] file and can be run with [[GHC/GHCi|ghci]] or [[hugs]]: So cut paste change and run (in [[Haskell mode for Emacs |emacs]] for instance) while reading it...'''<br />
<br />
==A simple evaluator==<br />
<br />
Let's start with something simple: suppose we want to implement a new<br />
programming language. We just finished with<br />
[http://swiss.csail.mit.edu/classes/6.001/abelson-sussman-lectures/ Abelson and Sussman's Structure and Interpretation of Computer Programs] <br />
and we want to test what we have learned.<br />
<br />
Our programming language will be very simple: it will just compute the<br />
sum of two terms.<br />
<br />
So we have just one primitive operation (Add) that takes two constants<br />
and calculates their sum.<br />
<br />
Moreover we have just one kind of [[algebraic datatype]]: Con a, which is an Int.<br />
<br />
For instance, something like:<br />
<br />
(Add (Con 5) (Con 6))<br />
<br />
should yield:<br />
<br />
11<br />
<br />
===The basic evaluator===<br />
<br />
We will implement our language with the help of a data [[type]]<br />
[[constructor]] such as:<br />
<br />
<div id="BasicEval"><br />
<haskell><br />
<br />
> module TheMonadicWay where<br />
> data Term = Con Int<br />
> | Add Term Term<br />
> deriving (Show)<br />
<br />
</haskell><br />
<br />
After that we build our interpreter:<br />
<br />
<haskell><br />
<br />
> eval :: Term -> Int<br />
> eval (Con a) = a<br />
> eval (Add a b) = eval a + eval b<br />
<br />
</haskell><br />
<br />
That's it. Just an example:<br />
<br />
*TheMonadicWay> eval (Add (Con 5) (Con 6))<br />
11<br />
*TheMonadicWay><br />
<br />
Very very simple. The evaluator checks if its [[argument]] is of the form <hask>Con Int</hask>. When it is, the [[function]] just returns the <hask>Int</hask>.<br />
<br />
If the argument is not of the form <hask>Con</hask>, but it is of the form <hask>Add Term Term</hask>, it evaluates the first <hask>Term</hask> and sums the result with the result of the evaluation of the second <hask>Term</hask>.<br />
<br />
As you may understand, our evaluator uses some of the powerful<br />
features of Haskell type system. Instead of writing a [[Parsing expressions and statements|parser]] that takes a string (the user input) and transforms that string into an expression to be evaluated, we use the two type constructors defined for our data type Term (Con and Add) to build the expression - such as<br />
(Add (Con 5) (Con 6)) - and to match the expression's elements in our<br />
"eval" function.<br />
<br />
== Some output, please!==<br />
<br />
Now, that's fine, but we'd like to add some features, like providing<br />
some output, to show how the computation was carried out.<br />
<br />
Well, but Haskell is a pure functional language, with no side effects,<br />
we were told.<br />
<br />
Now we seem to be wanting to create a side effect of the computation,<br />
its output, and be able to stare at it...<br />
<br />
If we had some global variable to store the out that would be<br />
simple...<br />
<br />
But we can create the output and carry it along the computation,<br />
concatenating it with the old one, and present it at the end of the<br />
evaluation together with the evaluation of the expression given to our<br />
evaluator/interpreter!<br />
<br />
===The basic evaluator with output===<br />
<br />
Simple and neat:<br />
<div id="BasivEvalO"><br />
<haskell><br />
<br />
> type MOut a = (a, Output)<br />
> type Output = String<br />
> <br />
> formatLine :: Term -> Int -> Output<br />
> formatLine t a = "eval (" ++ show t ++ ") <= " ++ show a ++ " - " <br />
> <br />
> evalO :: Term -> MOut Int<br />
> evalO (Con a) = (a, formatLine (Con a) a)<br />
> evalO (Add t u) = ((a + b),(x ++ y ++ formatLine (Add t u) (a + b)))<br />
> where (a, x) = evalO t<br />
> (b, y) = evalO u<br />
<br />
</haskell><br />
<br />
Now we have what we want. But we had to change our evaluator quite a<br />
bit. <br />
<br />
First we added a function, formatLine, that takes an argument of type<br />
Term (the expression to be evaluated), one of type Int (the result of<br />
the evaluation of Term) and gives back an output of type Output (that<br />
is a synonymous of String). This is just a helper function to format<br />
the string to output. Not very interesting at all.<br />
<br />
The evaluator itself changed quite a lot! Now it has a different type<br />
signature: it takes an argument of type Term and produces a new type,<br />
we called it MOut, that is actually a compound pair of a variable type<br />
a (an Int in our evaluator) and a type Output, a string.<br />
<br />
So our evaluator, now, will take a Term (the type of the expressions<br />
in our new programming language) and will produce a pair, composed of<br />
the result of the evaluation (an Int) and the Output, a string.<br />
<br />
So far so good. But what's happening inside the evaluator?<br />
<br />
The first part will just return a pair with the number evaluated ("a")<br />
and the output formatted by formatLine.<br />
<br />
The second part does something more complicated: it returns a pair<br />
composed by <br />
1. the result of the evaluation of the right Term summed to the result<br />
of the evaluation of the second Term<br />
2. the output: the concatenation of the output produced by the<br />
evaluation of the right Term, the output produced by the evaluation of<br />
the left Term (each this evaluation returns a pair with the number and<br />
the output), and the formatted output of the evaluation.<br />
<br />
Let's try it:<br />
*TheMonadicWay> evalO (Add (Con 5) (Con 6))<br />
(11,"eval (Con 5) <= 5 - eval (Con 6) <= 6 - eval (Add (Con 5) (Con 6)) <= 11 - ")<br />
*TheMonadicWay><br />
<br />
It works! Let's put the output this way:<br />
eval (Con 5) <= 5 - <br />
eval (Con 6) <= 6 - <br />
eval (Add (Con 5) (Con 6)) <= 11 -<br />
<br />
Great! We are able to produce a side effect of our evaluation and<br />
present it at the end of the computation, after all.<br />
<br />
Let's have a closer look at this expression:<br />
<haskell><br />
<br />
evalO (Add t u) = ((a + b),(x ++ y ++ formatLine (Add t u) (a + b)))<br />
where (a, x) = evalO t<br />
(b, y) = evalO u<br />
<br />
</haskell><br />
<br />
Why all that? The problem is that we need:<br />
* "a" and "b" to calculate their sum (a + b), that will be the first element of the compund pair rapresenting the type (MOut) our evaluator will return <br />
* "x and "y" (the output of each evaluation) to be concatenated with the ourput of formatLine by the expression (x ++ y ++ formatLine(...)): this will be the second element of the compound pair MOut, the string part.<br />
<br />
So we need to separate the pairs produced by "evalO t" and "evalO u".<br />
<br />
We do that within the where clause (remember: evalO now produces a value of type<br />
MOut Int, i.e. a pair of an Int and a String).<br />
<br />
Then we use the single element, "extraded" within the where clause, to<br />
return a new MOut composed by <br />
<br />
((a + b),(x ++ y ++ formatLine (Add t u) (a + b))).<br />
------ -------------------------------------<br />
Int Output = String<br />
<br />
== Let's go monadic==<br />
<br />
Is there a more general way of doing so?<br />
<br />
Let's analyze the evaluator from another perspective. From the type<br />
perspective.<br />
<br />
We solved our problem by creating a new type, a pair of an Int (the<br />
result of the evaluation) and a String (the output of the process of<br />
evaluation).<br />
<br />
The first part of the evaluator does nothing else but creating, from a<br />
value of type Int, an object of type MOut Int (Int,Output). It does so<br />
by creating a pair with that Int and some text produced by formatLine.<br />
<br />
The second part evaluates the two Term(s) and "stores" the values thus<br />
produced in some variables to be use later to compute the output.<br />
<br />
Let's focus on the "stores" action. The correct term should be<br />
"binds".<br />
<br />
Take a function:<br />
<haskell><br />
f x = x + x<br />
</haskell><br />
"x" appears on both sides of the expression. We say that on the right<br />
side "x" is bound to the value of x given on the left side.<br />
<br />
So<br />
<haskell><br />
f 3<br />
</haskell><br />
binds x to 3 for the evaluation of the expression "x + x".<br />
<br />
Our evaluator binds "a" and "x" / "b" and "y" with the evaluation of<br />
"evalO t" and "evalO u" respectively. <br />
<br />
Then "a","b","x" and "y" will be used in the evaluation of<br />
((a+b),(x++y++formatLine)), that will produce a value of type MOut Int:<br />
<br />
<pre><br />
<br />
((a + b),(x ++ y ++ formatLine (Add t u) (a + b))).<br />
------ -------------------------------------<br />
\ / \ /<br />
Int Output = String<br />
---------------------------------<br />
\ /<br />
MOut Int <br />
</pre><br />
<br />
The binding happens in the "where" clause:<br />
<haskell><br />
where (a, x) = evalO t<br />
(b, y) = evalO u<br />
</haskell><br />
<br />
We know that there is an ad hoc operator for binding variables to a<br />
value: lambda, or \.<br />
<br />
Indeed f x = x + x is syntactic sugar for:<br />
<haskell><br />
f = \x -> x + x<br />
</haskell><br />
When we write f 3 we are actually binding "x" to 3 within what's next<br />
"->", that will be used (substituted) for evaluating f 3.<br />
<br />
So we can try to abstract this phenomenon.<br />
<br />
===Monadic evaluator with output===<br />
What we need is a function that takes our composed type MOut Int and a<br />
function in order to produce a new MOut Int, concatenating the<br />
output of the computation of the first with the output of the<br />
computation of the second.<br />
<br />
This is what bindM does:<br />
<br />
<haskell><br />
<br />
> bindM :: MOut a -> (a -> MOut b) -> MOut b<br />
> bindM m f = (b, x ++ y)<br />
> where (a, x) = m<br />
> (b, y) = f a<br />
<br />
</haskell><br />
<br />
It takes:<br />
* "m": the compound type MOut Int carrying the result of an "eval Term",<br />
* a function "f". This function will take the Int ("a") extracted by the evaluation of "m" ((a,x)=m). This function will produce a new pair: a new Int produced by a new evaluation; some new output.<br />
<br />
bindM will return the new Int in pair with the concatenated outputs<br />
resulting from the evaluation of "m" and "f a".<br />
<br />
As you see, we took the binding part out from evalO and put it in this new function.<br />
<br />
So let's write the new version of the evaluator, that we will call evalM_1:<br />
<br />
<haskell><br />
<br />
> evalM_1 :: Term -> MOut Int<br />
> evalM_1 (Con a) = (a, formatLine (Con a) a)<br />
> evalM_1 (Add t u) = bindM (evalM_1 t) (\a -> <br />
> bindM (evalM_1 u) (\b -> <br />
> ((a + b), formatLine (Add t u) (a + b))<br />
> )<br />
> )<br />
<br />
</haskell><br />
<br />
Ugly, isn't it?<br />
<br />
Let's start from the outside:<br />
<br />
<haskell><br />
bindM (evalM_1 u) (\b -> ((a + b), formatLine (Add t u) (a + b)))<br />
</haskell><br />
<br />
bindM takes the result of the evaluation "evalM_1 u", a type Mout Int,<br />
and a function. It will extract the Int from that type and use it to<br />
bind "b".<br />
<br />
So in bindM (evalM_1 u) (\b ->) "b" will be bound to the value<br />
returned by evalM_1 u, and this bound variable will be available in<br />
what comes after "->" as a bound variable (not free).<br />
<br />
Then the outer part (bindM (evalM_1 t) (\a...) will bind "a" to the<br />
value returned "evalM_1 t", the result of the evaluatuion of the first<br />
Term. This value is needed to evaluate "((a+b), formatLine...) and<br />
produce our final MOut Int.<br />
<br />
We can try to explain "bindM" in a different way by using more descriptive names.<br />
<br />
As we have seen, "bindM" extracts the Int part from our type. The Int<br />
part will be used for further computations and the Output part will be<br />
concatenated. As a result we will have a new pair with a new Int and<br />
an accumulated Output.<br />
<br />
The new version of "bindM":<br />
<haskell><br />
<br />
> getIntFromType typeMOut doSomething = (newInt,oldOutput ++ newOutput)<br />
> where (oldInt,oldOutput) = typeMOut<br />
> (newInt,newOutput) = (doSomething oldInt)<br />
<br />
</haskell><br />
<br />
As you can see it does the very same things that "bindM" does: it<br />
takes something of type MOut and a function to perform some<br />
computation with the Int part. <br />
<br />
In the "where" clause, the old Int and the old output<br />
will be extracted from our type MOut (first line of the "where"<br />
clause). <br />
<br />
A new Int and a new output will be extracted from evaluating<br />
(doSomething oldInt) in the second line.<br />
<br />
Our function will return the new Int and the concatenated outputs.<br />
<br />
We do not need to define our doSomething function, because it will be<br />
an anonymous function:<br />
<br />
<haskell><br />
<br />
> evaluator (Con a) = (a, "output-")<br />
> evaluator (Add t u) = <br />
> getIntFromType (evaluator t) <br />
> (\firstInt -> getIntFromType (evaluator u) <br />
> (\secondInt -> ((firstInt + secondInt),("-newoutput"))))<br />
<br />
</haskell><br />
<br />
As you can see we are feeding our "getIntFromType" with the evaluation<br />
of an expression ("evaluator t" and "evaluator u"). The second<br />
argument of "getIntFromType" is an anonymous function that takes the<br />
"oldInt" and does something with it.<br />
<br />
So we have a series of nested anonymous functions. Their arguments<br />
("\firstInt" and "\secondInt") will be used to produce the computation<br />
we need ("(firstInt + secondInt). Moreover "getIntFromType" will take<br />
care of concatenating the outputs.<br />
<br />
This is the result:<br />
<br />
*TheMonadicWay> evaluator (Add (Con 5) (Con 6))<br />
(11,"output-output--newoutput")<br />
*TheMonadicWay> <br />
<br />
Going back to our "bindM", we can now use lambda notation to write our<br />
evaluator in a more convinient way:<br />
<br />
<haskell><br />
<br />
> evalM_2 :: Term -> MOut Int<br />
> evalM_2 (Con a) = (a, formatLine (Con a) a)<br />
> evalM_2 (Add t u) = evalM_2 t `bindM` \a -><br />
> evalM_2 u `bindM` \b -><br />
> ((a + b), (formatLine (Add t u) (a + b)))<br />
<br />
</haskell><br />
<br />
Now, look at the first part:<br />
<br />
<haskell><br />
evalM_2 (Con a) = (a, formatLine (Con a) a)<br />
</haskell><br />
<br />
We could use a more general way of creating some output. <br />
<br />
We can create a function that takes an Int and returns the type MOut<br />
Int. We do that by pairing the received Int with an empty string "".<br />
<br />
This will be a general way of creating an object with type MOut Int starting from an Int.<br />
<br />
Or, more generaly, a function that takes something of a variable type<br />
a, and return an object of type MOut a, a coumpunt object made up of<br />
an element of type a, and one of type String.<br />
<br />
There it is:<br />
<br />
<haskell><br />
<br />
> mkM :: a -> MOut a<br />
> mkM a = (a, "")<br />
<br />
</haskell><br />
<br />
As you can see, this function will just push an Int and an empty<br />
string ("") inside our type MOut.<br />
<br />
Then we need a method of inserting some text in our object of type<br />
MOut. So we will take a string and return it paired with a void<br />
element "()":<br />
<br />
<haskell><br />
<br />
> outPut :: Output -> MOut ()<br />
> outPut x = ((), x)<br />
<br />
</haskell><br />
<br />
Very simple: we have a string "x" (Output) and create a pair with a ()<br />
instead of an Int, and the output.<br />
<br />
You can see this function as one that pushes a string, paired with a<br />
void int, inside our type MOut.<br />
<br />
Now we can rewrite:<br />
<haskell><br />
evalM_2 (Con a) = (a, formatLine (Con a) a)<br />
</haskell><br />
using the bindM function:<br />
<haskell><br />
evalM_2 (Con a) = outPut (formatLine (Con a) a) `bindM` \_ -> mkM a<br />
</haskell><br />
<br />
First we create an object of type MOut with the Int part (). As you<br />
see bindM will not use it ("\_"), but will concatenate the String part<br />
with the result of mkM, which in turn is the empty string "".<br />
<br />
In other words, first we insert the Output part (a string) in our<br />
MOut, and then we insert the Int paired with an empty string: "bindM"<br />
will not use the void int (the anonymous function will not use it's<br />
argument: "\_"), but will take care of concatenating the non empty<br />
string inserted by "outPut" with the empty one inserted by "mkM".<br />
<br />
Let's rewrite the evaluator:<br />
<br />
<haskell><br />
<br />
> evalM_3 :: Term -> MOut Int<br />
> evalM_3 (Con a) = outPut (formatLine (Con a) a) `bindM` \_ -> <br />
> mkM a<br />
> evalM_3 (Add t u) = evalM_3 t `bindM` \a -><br />
> evalM_3 u `bindM` \b -><br />
> outPut (formatLine (Add t u) (a + b)) `bindM` \_ -> <br />
> mkM (a + b)<br />
<br />
</haskell><br />
<br />
Well, this is fine, definetly better then before, anyway.<br />
<br />
Still we use `bindM` \_ -> that binds something we do not use (_). We<br />
could write a function for this specific case, when we concatenate<br />
computations without the need of binding variables for later uses.<br />
Let's call it `combineM`:<br />
<br />
<haskell><br />
<br />
> combineM :: MOut a -> MOut b -> MOut b<br />
> combineM m f = m `bindM` \_ -> f<br />
<br />
</haskell><br />
<br />
This is just something that will allow us to write the evaluator in a<br />
more concise way. <br />
<br />
So the new evaluator:<br />
<br />
<haskell><br />
<br />
> evalM :: Term -> MOut Int<br />
> evalM (Con a) = outPut (formatLine (Con a) a) `combineM` <br />
> mkM a<br />
> evalM (Add t u) = evalM t `bindM` \a -><br />
> evalM u `bindM` \b -><br />
> outPut (formatLine (Add t u) (a + b)) `combineM` <br />
> mkM (a + b)<br />
<br />
</haskell><br />
<br />
Let's put everything together (changing M into MO, so that this file<br />
will be still usable as a Literate Haskell file):<br />
<br />
<haskell><br />
<br />
> type MO a = (a, Out)<br />
> type Out = String<br />
<br />
> mkMO :: a -> MO a<br />
> mkMO a = (a, "")<br />
<br />
> bindMO :: MO a -> (a -> MO b) -> MO b<br />
> bindMO m f = (b, x ++ y)<br />
> where (a, x) = m<br />
> (b, y) = f a<br />
<br />
> combineMO :: MO a -> MO b -> MO b<br />
> combineMO m f = m `bindM` \_ -> f<br />
<br />
> outMO :: Out -> MO ()<br />
> outMO x = ((), x)<br />
<br />
> evalMO :: Term -> MO Int<br />
> evalMO (Con a) = outMO (formatLine (Con a) a) `combineMO`<br />
> mkMO a<br />
> evalMO (Add t u) = evalMO t `bindMO` \a -><br />
> evalMO u `bindMO` \b -><br />
> outMO (formatLine (Add t u) (a + b)) `combineMO` <br />
> mkMO (a + b)<br />
<br />
</haskell><br />
<br />
==What does bind bind?==<br />
<br />
<div id="Bind"><br />
The evaluator looks like:<br />
<haskell><br />
evalM t >>= \a -> evalM u >>= \b -> outPut "something" >>= \_ -> mkM (a +b)<br />
</haskell><br />
where >>= is bindMO, obviously.<br />
<br />
Let's do some substitution, writing the type of their output of each function:<br />
* evalMO t => (a,Out) - where a is Int<br />
* evalMO u => (b,Out) - where b is the same of a, an Int, but with a different value<br />
* outMO Out = ((),Out)<br />
* mkMO (a+b) => ((a+b),Out) - where (a+b) is the same of a and b, but with a different value from either a and b<br />
<br />
<pre><br />
B | (a,Out) >>= \a -> (b,Out) >>= \b -> ((),Out) >>= \_ >>= ((a + b), Out)---\<br />
i | V V V V V V V V ^ ^ ^ ^ |\<br />
n | |__|________^ | | ^ | | | | | | | MOut Int <=> ((a+b), Out)<br />
d |_____|__(++)__|_Out_|__|__(++)__V_Out_|___|___(++)_|_(++)__|___|____|_____|/<br />
i | | |______(b)__|_____|_____(b)____|__(b)__|___|<br />
n | |_________(a)___________|____________|__(a)__|<br />
g | |_____()_____|<br />
<br />
</pre><br />
<br />
Clear, isn't it?<br />
<br />
"bindMO" is just a function that takes care of gluing together, inside<br />
a data type, a sequence of computations!<br />
<br />
== Some sugar, please!==<br />
Now our evaluator has been completely transformed into a monadic<br />
evaluator. That's what it is: a monad.<br />
<br />
We have a function that constructs an object of type MO Int, formed by<br />
a pair: the result of the evaluation and the accumulated<br />
(concatenated) output.<br />
<br />
The process of accumulation and the act of parting the MO Int into its<br />
component is buried into bindMO, now, that can also preserve some<br />
value for later uses.<br />
<br />
So we have:<br />
* MO a type constructor for a type carrying a pair composed by an Int and a String;<br />
* bindMO, that gives a direction to the process of evaluation: it concatenates computations and captures some side effects we created (the direction is given by the changes in the Out part: there's a "before" when Out was something and there's a "later" when Out is something else).<br />
* mkMO lets us create an object of type MO Int starting from an Int.<br />
<br />
As you see this is all we need to create a monad. In other words<br />
monads arise from the type system and the lambda calculus. Everything<br />
else is just syntactic sugar.<br />
<br />
So, let's have a look at that sugar: the famous do-notation!<br />
<br />
===Monadic evaluator with output in do-notation===<br />
<br />
In order to be able to use the "do-notation" we need to define a new<br />
type and make it an instance of the Monad class. To make a new type an<br />
instance of the Monad class we will have to define the two methods of<br />
this class: (>>=) and "return".<br />
<br />
This is not going to be difficult, because we already created these<br />
two methods: "bindM" and "mkM". Now we will have to rewrite them in<br />
order to reflect the fact that we are not going to use a type, for our<br />
evaluator, that is a synonymous of other types, as we did before.<br />
Indeed our MOut was defined with the "type" keyword. Now we will have<br />
to define a "real" new type with either "newtype" or "data". Since we<br />
are not going to need multiple constructors, we will use "newtype".<br />
<br />
<div id="MonadicEvalIO"><br />
<haskell><br />
<br />
> newtype Eval_IO a = Eval_IO (a, O)<br />
> deriving (Show)<br />
> type O = String<br />
<br />
</haskell><br />
<br />
This is our new type: it will have a single type constructor, whose<br />
name is the same of the type name ("Eval_IO"). The type constructor<br />
takes a parameter ("a"), a variable type, and will build a type formed<br />
by a type "a" (an Int in our case) and a String (O is indeed<br />
synonymous of String).<br />
<br />
We now need to define our "bind" function to reflect the fact that we<br />
are now using a "real" type, and, to unpack its content, we need to do<br />
pattern-matching we the type constructor "Eval_IO". Moreover, since we<br />
must return an Eval_IO type, we will use the type constructor also for<br />
building the new type with the new int and the concatenated output.<br />
<br />
For the rest our "bind" function will be identical to the one we<br />
defined before.<br />
<br />
We are going to use very descriptive names:<br />
<br />
<haskell><br />
<br />
> getInt monad doSomething = Eval_IO (newInt,oldOutput ++ newOutput)<br />
> where Eval_IO (oldInt,oldOutput) = monad<br />
> Eval_IO (newInt,newOutput) = (doSomething oldInt)<br />
<br />
</haskell><br />
<br />
As you can see, we are using Eval_IO to build the result of the<br />
computation to be returned by getInt: "Eval_IO (newInt,oldOutput ++<br />
newOutput)". And we are using it to match the internal components of<br />
our type in the "where" clause.<br />
<br />
We also need to create a function that, like mkO, will take an Int and,<br />
using the type constructor "Eval_IO", will create an object of type<br />
Eval_IO with that Int and an empty string:<br />
<br />
<haskell><br />
<br />
> createEval_IO :: a -> Eval_IO a<br />
> createEval_IO int = Eval_IO (int,"")<br />
<br />
</haskell><br />
<br />
And, finally, we need a function that will insert, in our type, a<br />
string and a void ():<br />
<br />
<haskell><br />
<br />
> print_IO :: O -> Eval_IO ()<br />
> print_IO string = Eval_IO ((), string)<br />
<br />
</haskell> <br />
<br />
With these functions we could write our monadic evaluator without the<br />
"do-notation" like this:<br />
<br />
<haskell><br />
<br />
> evalM_4 :: Term -> Eval_IO Int<br />
> evalM_4 (Con a) = createEval_IO a<br />
> evalM_4 (Add t u) = evalM_4 t `getInt` \a -><br />
> evalM_4 u `getInt` \b -><br />
> print_IO (formatLine (Add t u) (a + b)) `getInt` \_ -><br />
> createEval_IO (a + b)<br />
<br />
</haskell><br />
<br />
It is very similar to the previous evaluator, as you can see. The only<br />
differences are related to the fact that we are now using a "real"<br />
type and not a type synonymous: this requires the use of the type<br />
constructor to match the type and its internal part (as we do in the<br />
"where" clause of our "bind" function: "getInt") or to build the type<br />
(as we do in the "bind" function to return the new Int with the<br />
concatenated output).<br />
<br />
Running this evaluator will produce:<br />
<br />
*TheMonadicWay> evalM_4 (Add (Con 6) (Con 12))<br />
Eval_IO (18,"eval (Add (Con 6) (Con 12)) <= 18 - ")<br />
*TheMonadicWay> <br />
<br />
Now we have everything we need to declare our type, Eval_IO, as an<br />
instance of the Monad class:<br />
<haskell><br />
<br />
> instance Monad Eval_IO where<br />
> return a = createEval_IO a<br />
> (>>=) m f = getInt m f<br />
<br />
</haskell><br />
<br />
As you see we are just using our defined functions as methods for our<br />
instance of the Monad class.<br />
<br />
This is all we need to do. Notice that we do not have to define the<br />
"combineM" function, for chaining computation, as we do with "getInt",<br />
without binding variables for later use within the series of nested<br />
anonymous functions (the "doSomething" part) that will form the "do"<br />
block.<br />
<br />
This function comes for free by just defining our type as an instance<br />
of the Monad class. Indeed, if you look at the definition of the Monad<br />
class in the Prelude you see that "combineM", or (>>) is deduced by<br />
the definition of (>>=):<br />
<br />
<haskell><br />
class Monad m where<br />
return :: a -> m a<br />
(>>=) :: m a -> (a -> m b) -> m b<br />
(>>) :: m a -> m b -> m b<br />
fail :: String -> m a<br />
<br />
-- Minimal complete definition: (>>=), return<br />
p >> q = p >>= \ _ -> q<br />
fail s = error s<br />
</haskell><br />
<br />
You can see that the "combineM"" method (or (>>)) is automatically<br />
derived by the "bindMO" (or >>=) method:<br />
<br />
<haskell><br />
p >> q = p >>= \ _ -> q<br />
</haskell><br />
<br />
We can now write our evaluator using the do-notation:<br />
<br />
<haskell><br />
<br />
> eval_IO :: Term -> Eval_IO Int<br />
> eval_IO (Con a) = do print_IO (formatLine (Con a) a)<br />
> return a<br />
> eval_IO (Add t u) = do a <- eval_IO t<br />
> b <- eval_IO u<br />
> print_IO (formatLine (Add t u) (a + b))<br />
> return (a + b)<br />
<br />
</haskell><br />
<br />
As you can see the anonymous functions are gone. Instead we use this:<br />
a <- eval_IO t<br />
<br />
This seems like an assignment, that cannot be possible in Haskell. In<br />
fact it is just the way our anonymous function's arguments is bound<br />
within a do block.<br />
<br />
Even if it does not seem like a series of nested anonymous functions,<br />
this is what actually a do block is.<br />
<br />
Our monad is defined by three elements: <br />
* a type, with its type constructor(s);<br />
* a bind method: it will bind an unwritten anonymous function's argument to the value of the Int part of our type, or more generally, of the variable type "a". It will also create a series of anonymous functions: a line for each function;<br />
* a "return" function, to insert, into out type, a value of type Int, or, more generally, a value of variable type "a".<br />
<br />
Additionally, we need a function to insert a string in our type,<br />
string that the derived "bind" (>>) will concatenate ignoring the void<br />
(), our "print_IO".<br />
<br />
Within a do block we can thus perform only tree kinds of operations:<br />
* a computation that produces a new Int, packed inside our monad's type, to be extracted and bound to a variable (an anonymous function's argument really):<br />
** this operation requires a binding (">>= \varName ->"), translated into "varName <- computation"<br />
** example: a <- eval_IO t<br />
* a computation that inserts a string into our monad, a string to be concatenated, without the need of binding a variable (an anonymous function's argument really):<br />
** this operation does not require a binding: it will be ">>= \_ ->", i.e. ">>", translated into a simple new line<br />
** example: print_IO (formatLine (Add t u) (a + b))<br />
* a computation that inserts an Int into our monad without the need of binding a variable (an anonymous function's argument really):<br />
** this operation is carried out by the <hask>return</hask> method (usually at the end of a do block, useless in the middle)<br />
** example <hask>return (a + b)</hask><br />
<br />
To sum up, within a block, "do" will take care of creating and<br />
nesting, for us, all the needed anonymous functions so that bound<br />
variables will be available for later computations.<br />
<br />
In this way we can emulate a direction of our computation, a "before"<br />
and an "after", even within a pure functional language. And we can use<br />
this possibility to create and accumulate side effects, like output.<br />
<br />
Let's see the evaluator with output in action:<br />
*TheMonadicWay> eval_IO (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <br />
Eval_IO (54,"eval (Con 6) <= 6 - eval (Con 16) <= 16 - eval (Con 20) <= 20 - eval (Con 12) <= 12 - \<br />
eval (Add (Con 20) (Con 12)) <= 32 - eval (Add (Con 16) (Add (Con 20) (Con 12))) <= 48 - \<br />
eval (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <= 54 - ")<br />
*TheMonadicWay> <br />
<br />
Let's format the output part:<br />
eval (Con 6) <= 6 <br />
eval (Con 16) <= 16 <br />
eval (Con 20) <= 20 <br />
eval (Con 12) <= 12 <br />
eval (Add (Con 20) (Con 12)) <= 32 <br />
eval (Add (Con 16) (Add (Con 20) (Con 12))) <= 48 <br />
eval (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <= 54 <br />
<br />
==[[Type]] and [[Newtype]]: What happened to our output?==<br />
<br />
Well, actually something happened to the output. Let's compare the<br />
output of evalMO (the monadic evaluator written without the<br />
do-notation) and eval_IO:<br />
<br />
*TheMonadicWay> evalMO (Con 6)<br />
(6,"eval (Con 6) <= 6 - ")<br />
*TheMonadicWay> eval_IO (Con 6)<br />
Eval_IO (6,"eval (Con 6) <= 6 - ")<br />
*TheMonadicWay> <br />
<br />
They look almost the same, but they are not the same: the output of<br />
eval_IO has the Eval_IO stuff. It must be related to the changes we<br />
had to do to our evaluator in order to use the do-conation, obviously.<br />
<br />
We can now review some of our basic knowledge of Haskell's type<br />
system.<br />
<br />
What's changed? First the type definition. We have now:<br />
<br />
<haskell><br />
newtype Eval_IO a = Eval_IO (a, O)<br />
deriving (Show)<br />
</haskell><br />
<br />
instead of <br />
<br />
<haskell><br />
type MO a = (a, Out)<br />
</haskell><br />
<br />
Now <hask>return a</hask> is the product of the application of the<br />
type constructor Eval_IO to the pair that are going to form our monad.<br />
<br />
"return" takes an Int and inserts it into our monad. It will also<br />
insert an empty String "" that (>>=) or (>>) will then concatenate in<br />
the sequence of computations they glue together.<br />
<br />
The same for (>>=). It will now return something constructed by<br />
Eval_IO: <br />
<br />
* "newInt", the result of the application of "doSomething" to "oldInt" (better, the binding of "oldInt" in "doSomething");<br />
* the concatenation of "oldOutput" (matched by <hask>Eval_IO (oldInt, oldOutput)</hask> with the evaluation of "monad" - "eval_IO t") and "newOutput", (matched by "Eval_IO(newInt,newOutput)" with the evaluation of "(doSomething monad)" - "eval_IO u").<br />
<br />
That is to say: in the "where" clause, we are matching for the<br />
elements paired in a type Eval_IO: this is indeed the type of "monad"<br />
(corresponding to "eval_IO t" in the body of the evaluator) and<br />
"(doSomething monad)" (where "doSomething" correspond to the<br />
evaluation of "eval_IO u" within an anonymous function with \oldInt as<br />
its argument, argument bound to the result of the previous evaluation<br />
of "monad", that is to say "eval_IO t").<br />
<br />
And so, "Eval_IO (oldInt,oldOutput) = monad" means: match "oldInt" and<br />
"oldOutput", paired in a type Eval_IO, and that are produced by the<br />
evaluation of "monad" (that is to say: "eval_IO t"). The same for<br />
Eval_IO (newInt,newOutput): match "newInt" and "newOutput" produced by<br />
the evaluation of "(doSomething monad)".<br />
<br />
So the output of the evaluator is now not simply a pair made of and<br />
Int and a String. It is a specific type (Eval_IO) that happens to<br />
carry a pair of an Int and a String. But, if we want the Int and the<br />
string, we have to extract them from the Eval_IO type, as we do in the<br />
"where" clause: we ''unpack'' our type object (let's call it with its<br />
name: our monad!) and take out the Int and the String to feed the next<br />
function application and the output generation.<br />
<br />
The same to insert something in our monad: if we want to create a pair<br />
of an Int and a String, pair of type Eval_IO, we now have to ''pack''<br />
them together by using our type constructor, feeding it with a pair<br />
composed by and Int and a String. This is what we do with the "return"<br />
method of out monad and with "print_IO" function, where:<br />
* return insert into the monad an Int;<br />
* print_IO insert into the monad a String.<br />
<br />
So, why cannot we use the old <hask>type MO a = (a, Out)</hask> that<br />
did not required all this additional work (apart the need to<br />
specifically define (>>)?<br />
<br />
Type MO is just a synonymous for (a,Out): the two can be substituted<br />
one for the other. That's it.<br />
<br />
We did not have to pack "a" and "Out" together with a type constructor<br />
to have a new type MO.<br />
<br />
As a consequence, we cannot use MO as an instance of Monad, and so, we<br />
cannot use with it the syntactic sugar we needed: the do-notation.<br />
<br />
That is to say: a type created with the "type" keyword cannot be an<br />
instance of a class, and cannot inherits its methods (in our case<br />
(>>=, >> and return). And without those methods the do-notation is not<br />
usable.<br />
<br />
==Errare monadicum est==<br />
<br />
Now that we have a basic understanding of what a monad is, and does,<br />
we will further explore it by making some changes to our evaluator.<br />
<br />
In this section we will se how to handle exceptions in our monadic<br />
evaluator.<br />
<br />
Suppose that we want to stop the execution of our monad if some<br />
conditions occurs. If our evaluator was to compute divisions, instead<br />
of sums, then we would like to stop the evaluator when a division by<br />
zero occurs, possibly producing some output, instead of the result of<br />
the evaluation of the expression, that explains what happened.<br />
<br />
Basic error handling.<br />
<br />
We will do so starting from the beginning once again...<br />
<br />
===The basic evaluator, non monadic, with exception===<br />
<br />
We just take our basic evaluator, without any output, and write a<br />
method to stop execution if a condition occurs: <br />
<br />
<haskell><br />
<br />
> data M a = Raise Exception<br />
> | Return a<br />
> deriving (Show)<br />
> type Exception = String<br />
<br />
</haskell><br />
<br />
Now, our monad is of datatype "M a" which can either be constructed<br />
with the "Raise" constructor, that takes a String (Exception is a<br />
synonymous of String), or by the "Return" constructor, that takes a<br />
variable type ("a"), an Int in our case.<br />
<br />
<haskell><br />
<br />
> evalE :: Term -> M Int<br />
> evalE (Con a) = Return a<br />
<br />
</haskell><br />
<br />
If evalE matches a Con it will construct a type Return with, inside, the content of the Con.<br />
<br />
<haskell><br />
<br />
> evalE (Add a b) = <br />
> case evalE a of<br />
> Raise e -> Raise e<br />
> Return a -><br />
> case evalE b of <br />
> Raise e -> Raise e<br />
> Return b -><br />
> if (a+b) == 42<br />
> then Raise "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else Return (a+b)<br />
<br />
</haskell><br />
<br />
If evalE matches an Add it will check if evaluating the first part<br />
produces a "Raise" or a "Return": in the first case it will return a<br />
"Raise" whose content is the same received. <br />
<br />
If instead the evaluation produces a value of a type matched by<br />
"Return", the evaluator will evaluate the second term of Add.<br />
<br />
If this returns a "Raise", a "Raise" will be returned all the way up<br />
the recursion, otherwise the evaluator will check whether a condition<br />
for raising a "Raise" exists. If not, it will return a "Return" with<br />
the sum inside.<br />
<br />
Test it with:<br />
<br />
evalE (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2)))<br />
<br />
<br />
===The basic evaluator, monadic, with exceptions===<br />
<br />
In order to produce a monadic version of the previous evaluator, the<br />
one that raises exceptions, we just need to abstract out from the<br />
evaluator all that case analysis.<br />
<br />
<haskell><br />
<br />
> data M1 a = Except Exception<br />
> | Ok {showM :: a }<br />
> deriving (Show)<br />
<br />
</haskell><br />
<br />
The data type didn't change at all. Well, we changed the name of the<br />
Return type constructor (now Ok) so that this constructor can coexist<br />
with the previous one in the same Literate Haskell file.<br />
<br />
<div id="MonadicEvalE"><br />
<haskell><br />
<br />
> instance Monad M1 where<br />
> return a = Ok a<br />
> m >>= f = case m of<br />
> Except e -> Except e<br />
> Ok a -> f a<br />
<br />
</haskell><br />
<br />
Binding operations are now very easy. Basically we check:<br />
* if the result of the evaluation of "m" produces an exception (first match: Except e ->...), in which case we return its content by constructing our M1 Int with the "Raise" constructor".<br />
* if the result of the evaluation of "m" is matched with the "Ok" constructor, we get its content and use it to bind the argument of "f" to its value.<br />
<br />
<hask>return a</hask> will just use the Ok type constructor for<br />
inserting "a" (in our case an Int) into M1 Int, the type of our monad.<br />
<br />
<haskell><br />
<br />
> raise :: Exception -> M1 a<br />
> raise e = Except e<br />
<br />
</haskell><br />
<br />
This is just a helper function to construct our "M1 a" type with the<br />
Raise constructor. It takes a string and returns a type (M1 a) to be<br />
matched with the "Raise" constructor.<br />
<br />
<haskell><br />
<br />
> eval_ME :: Term -> M1 Int<br />
> eval_ME (Con a) = do return a<br />
> eval_ME (Add t u) = do a <- eval_ME t<br />
> b <- eval_ME u<br />
> if (a+b) == 42<br />
> then raise "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
</haskell><br />
<br />
The evaluator itself is very simple. We bind "a" with the result of<br />
"eval_ME t", "b" with the result of "eval_ME u", and we check for a<br />
condition: <br />
* if the condition is met we raise an exception, that is to say: we return a value constructed with the "Raise" constructor. This value will be matched by ">>=" in the next recursion. And >>= will just return it all the way up the recursion.<br />
* if the condition is not met, we return a value constructed with the "Return" type constructor and go on with the recursion.<br />
<br />
Run with:<br />
<br />
eval_ME (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2)))<br />
<br />
It is noteworthy the fact that in our datatype definition we used a<br />
label field with a label selector (we called it showM), even though it<br />
was not used in our code. We will use this methodology later on.<br />
<br />
So, just to refresh your memory:<br />
<br />
<haskell><br />
<br />
> data Person = Person {name :: String,<br />
> age :: Int,<br />
> hobby :: String<br />
> } deriving (Show)<br />
<br />
> andreaRossato = Person "Andrea" 37 "Haskell The Monadic Way"<br />
> personName (Person a b c) = a<br />
<br />
</haskell><br />
<br />
will produce:<br />
*TheMonadicWay> andreaRossato<br />
Person {name = "Andrea", age = 37, hobby = "Haskell The Monadic Way"}<br />
*TheMonadicWay> personName andreaRossato<br />
"Andrea"<br />
*TheMonadicWay> name andreaRossato<br />
"Andrea"<br />
*TheMonadicWay> age andreaRossato<br />
37<br />
*TheMonadicWay> hobby andreaRossato<br />
"Haskell The Monadic Way"<br />
*TheMonadicWay> <br />
<br />
<br />
===Monadic evaluator with output and exceptions===<br />
<br />
We will now try to combine the [[The Monadic Way/Part I#MonadicEvalIO|output-producing monadic evaluator]] <br />
with [[The Monadic Way/Part I#MonadicEvalE| exception producing one]].<br />
<br />
<br />
<haskell><br />
<br />
> data M2 a = Ex Exception<br />
> | Done {unpack :: (a,O) }<br />
> deriving (Show)<br />
<br />
</haskell><br />
<br />
Now we need a [[algebraic datatype]] with two [[constructor]]s: one to produce a value type "M2 a" using "Ex String" and one for value type "M2 a" (Int in<br />
this case) using "Done a".<br />
<br />
'''Note''' that we changed the name of the exception type constructor<br />
from "Raise" to "Ex" just to make the two coexist in the same [[Literate programming|literate Haskell]] file.<br />
<br />
The constructor "Done a" is defined with a label selector: <hask>Done {unpack :: (a,O)}</hask> <br />
and is equivalent to <hask>Done (a,O)</hask>. <br />
<br />
The only difference is that, this way, we are also defining a method<br />
to retrieve the pair (a,O) (in our case "O" is a synonymous for<br />
String, whereas "a" is a variable type) from an object of type "Done<br />
a".<br />
<br />
<haskell><br />
<br />
> instance Monad M2 where<br />
> return a = Done (a, "")<br />
> m >>= f = case m of<br />
> Ex e -> Ex e<br />
> Done (a, x) -> case (f a) of<br />
> Ex e1 -> Ex e1<br />
> Done (b, y) -> Done (b, x ++ y)<br />
<br />
</haskell><br />
<br />
Now our binding operations gets more complicated by the fact that we<br />
have to concatenate the output, as we did before, '''and''' check for<br />
exceptions.<br />
<br />
It is not possible to do has we did in the [[The Monadic Way/Part I#MonadicEvalE| exception producing evaluator]], <br />
where we could check just for "m" (remember the "m" in the first run<br />
stands for "eval t").<br />
<br />
Since at the end we must return the output produced by the evaluation<br />
of "m" ''concatenated'' with the output produced by the evaluation of<br />
"f a" (where "a" is returned by "m", paired with "x" by "Done"), now<br />
we must check if we '''do have''' an output from "f a" produced by<br />
"Done".<br />
<br />
Indeed, now, "f a" can also produce a value constructed by "Ex", and<br />
this value does not contain the pair as the value produced by "Done".<br />
<br />
So, we evaluate "m": <br />
* if we match a value produced by type constructor "Ex" we return a value produced by type constructor "Ex" whose content is the one we extracted in the matching;<br />
* if we match a value produced by "Done" we match the pair it carries "(a,x)" and we analyze what "f a" returns:<br />
** if "f a" returns a value produced by "Ex" we extract the exception and we return it, constructing a value with "Ex"<br />
** if "f a" returns a value produced by "Done" we return "b" and the concatenated "x" and "y". <br />
<br />
And now the evaluator:<br />
<br />
<haskell><br />
<br />
> raise_IOE :: Exception -> M2 a<br />
> raise_IOE e = Ex e<br />
<br />
</haskell><br />
<br />
This is the [[function]] to insert an exception in our monad (M2): We take<br />
a String and produce a value applying the type constructor for exception "Ex" to its value.<br />
<br />
<haskell><br />
<br />
> print_IOE :: O -> M2 ()<br />
> print_IOE x = Done ((), x)<br />
<br />
</haskell><br />
<br />
The function to produce output is the very same of the one of the [[The Monadic Way/Part I#MonadicEvalIO|output-producing monadic evaluator]].<br />
<br />
<haskell><br />
<br />
> eval_IOE :: Term -> M2 Int<br />
> eval_IOE (Con a) = do print_IOE (formatLine (Con a) a)<br />
> return a<br />
> eval_IOE (Add t u) = do a <- eval_IOE t<br />
> b <- eval_IOE u<br />
> let out = formatLine (Add t u) (a + b)<br />
> print_IOE out<br />
> if (a+b) == 42<br />
> then raise_IOE $ out ++ "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
</haskell><br />
<br />
The evaluator procedure did not change very much from the one of the [[The Monadic Way/Part I#MonadicEvalIO|output-producing monadic evaluator]].<br />
<br />
We just added the case analysis to see if the condition for raising an exception is met.<br />
<br />
Running with<br />
<br />
eval_IOE (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2)))<br />
<br />
will produce <br />
<br />
Ex "eval (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2))) <= 42 - <br />
The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
<br />
Look at the <hask>let</hask> clause within the do-notation. We do not<br />
need to use the "let ... in" construction: since all [[bound variable]]s<br />
remain bound within a <hask>do</hask> procedure (see [[The Monadic Way/Part I#Bind|here]]), <br />
we do not need the "in" to specify "where" the variable "out" will be bound in!<br />
<br />
==We need a state==<br />
<br />
We will keep on adding complexity to our monadic evaluator and this<br />
time we will add a counter. We just want to count the number of<br />
iterations (the number of times "eval" will be called) needed to<br />
evaluate the expression.<br />
<br />
===The basic evaluator, non monadic, with a counter===<br />
<br />
As before we will start by adding this feature to our [[The Monadic Way Part I#BasicEval|basic evaluator]]. <br />
<br />
A method to count the number of iterations, since the lack of<br />
assignment and destructive updates (such as for i=0;i<10;i++;),<br />
is to add an argument to our function, the initial state, number that<br />
in each call of the function will be increased and passed to the next<br />
function call.<br />
<br />
And so, very simply:<br />
<br />
<haskell><br />
<br />
> -- non monadic<br />
> type St a = State -> (a, State)<br />
> type State = Int<br />
> evalNMS :: Term -> St Int<br />
> evalNMS (Con a) x = (a, x + 1)<br />
> evalNMS (Add t u) x = let (a, y) = evalNMS t x in<br />
> let (b, z) = evalNMS u y in<br />
> (a + b, z +1)<br />
<br />
</haskell><br />
<br />
Now evalNMS takes two arguments: the expression of type Term and an<br />
State (which is a synonymous for Int), and will produce a pair<br />
(a,State), that is to say a pair with a variable type "a" and an Int.<br />
<br />
The operations in the evaluator are very similar to the non monadic [[The Monadic Way Part I#BasivEvalO|output producing evaluator]].<br />
<br />
We are now using the "let ... in" clause, instead of the "where", and we are increasing the counter "z" the comes from the evaluation of the second term, but the basic operation are the same:<br />
* we evaluate "evalNMS t x" where "x" is the initial state, and we match and bind the result in "let (a, y) ... in"<br />
* we evaluate "evalNMS u y", where "y" was bound to the value returned by the previous evaluation, and we match and bind the result in "let (b, z) ... in"<br />
* we return a pair formed by the sum of the result (a+b) and the state z increased by 1. <br />
<br />
Let's try it:<br />
<br />
*TheMonadicWay> evalNMS (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2))) 0<br />
(42,7)<br />
*TheMonadicWay> <br />
<br />
As you see we must pass to "evalNMS"the initial state of our counter: 0.<br />
<br />
Look at the type signature of the function "evalNMS":<br />
<haskell><br />
evalNMS :: Term -> St Int<br />
</haskell><br />
<br />
From this signature you could argue that our function takes only<br />
'''one''' argument. But since our type St is defined with the "type"<br />
keyword, St can be substituted with what comes after the "=" sign. So,<br />
the real type signature of our function is:<br />
<br />
<haskell><br />
evalNMS :: Term -> State -> (Int,State)<br />
</haskell><br />
<br />
<div if="typeNewtype"><br />
Just to refresh your memory:<br />
<br />
<haskell><br />
<br />
> type IamAfunction a = (a -> a)<br />
> newtype IamNotAfunction a = NF (a -> a)<br />
> newtype IamNotAfunctionButYouCanUnPackAndRunMe a = F { unpackAndRun :: (a -> a) }<br />
<br />
> a = \x -> x * x<br />
<br />
> a1 :: IamAfunction Integer<br />
> a1 = a<br />
<br />
> a2 :: IamNotAfunction Integer<br />
> a2 = NF a<br />
<br />
> a3 :: IamNotAfunctionButYouCanUnPackAndRunMe Integer<br />
> a3 = F a<br />
<br />
</haskell><br />
<br />
<br />
*TheMonadicWay> a 4<br />
16<br />
*TheMonadicWay> a1 4<br />
16<br />
*TheMonadicWay> a2 4<br />
<br />
<interactive>:1:0:<br />
The function `a2' is applied to one arguments,<br />
but its type `IamNotAfunction Int' has only 0<br />
In the definition of `it': it = a2 4<br />
*TheMonadicWay> a3 4<br />
<br />
<interactive>:1:0:<br />
The function `a3' is applied to one arguments,<br />
but its type `IamNotAfunctionButYouCanUnPackAndRunMe Int' has only 0<br />
In the definition of `it': it = a3 4<br />
*TheMonadicWay> unpackAndRun a3 4<br />
16<br />
*TheMonadicWay><br />
<br />
This means that "a1" is a partial application hidden by a type<br />
synonymous. <br />
<br />
"a2" and "a3" are not function types. They are types that<br />
have a functional value. <br />
<br />
Moreover, since we defined the type constructor of type<br />
"IamNotAfunctionButYouCanUnPackAndRunMe", F, with a label field, in<br />
that label field we defined a method (a label selector) to "extract"<br />
the function from the type "IamNotAfunctionButYouCanUnPackAndRunMe",<br />
and run it:<br />
<br />
<haskell><br />
unpackAndRun a3 4<br />
</haskell><br />
<br />
And what about "a2"? Is it lost forever?<br />
<br />
Obviously not! We need to write a function that unpacks a type<br />
"IamNotAfunction", using its type constructor NF to match the internal<br />
function:<br />
<br />
<haskell><br />
<br />
> unpackNF :: IamNotAfunction a -> a -> a<br />
> unpackNF (NF f) = f<br />
<br />
</haskell><br />
<br />
and run:<br />
<br />
*TheMonadicWay> unpackNF a2 4<br />
16<br />
*TheMonadicWay> <br />
<br />
As you see, "unpackNF" definition is a partial application: we specify<br />
one argument to get a function that gets another argument.<br />
<br />
A label selector does the same thing.<br />
<br />
Later we will see the importance of this distinction, quite obvious<br />
for haskell gurus, but not for us. Till now.<br />
<br />
===The evaluator, monadic, with a counter===<br />
<br />
We will now rewrite our basic evaluator with the counter in<br />
do-notation.<br />
<br />
As we have seen, in order to do so we need:<br />
* a new type that we must declare as an instance of the Monad class;<br />
* a function for binding method (>>=) and a function for the "return" method, for the instance declaration; <br />
<br />
Now our type will be holding a function that will take the initial<br />
state 0 as we did before.<br />
<br />
In order to simplify the process of unpacking the monad each time to<br />
get the function, we will use a label sector:<br />
<br />
<haskell><br />
<br />
> newtype MS a = MS { unpackMSandRun :: (State -> (a, State)) }<br />
<br />
</haskell><br />
<br />
This is it: MS will be our type constructor for matching and for<br />
building our monad. "unpackMSandRun" will be the method to get the<br />
function out of the monad to feed it with the initial state of the<br />
counter, 0, to get our result.<br />
<br />
Then we need the "return" function that, as we have seen does nothing<br />
but inserting into our monad an Integer:<br />
<br />
<haskell><br />
<br />
> mkMS :: a -> MS a<br />
> mkMS int = MS (\x -> (int, x))<br />
<br />
</haskell><br />
<br />
"mkMS" will just take an Integer "a" and apply the MS type constructor<br />
to our anonymous function that takes an initial state and produces the<br />
final state "x" and the integer "a".<br />
<br />
In other words, we are just creating our monad with inside an Integer.<br />
<br />
Our binding function will be a bit more complicated then before. We<br />
must create a type that holds an anonymous function with elements to<br />
be extracted from our type and passed to the anonymous function that<br />
comes next:<br />
<br />
<haskell><br />
<br />
> bindMS :: MS a -> (a -> MS b) -> MS b<br />
> bindMS monad doNext = MS $ \initialState -> <br />
> let (oldInt, oldState) = unpackMSandRun monad initialState in<br />
> let (newInt, newState) = unpackMSandRun (doNext oldInt) oldState in<br />
> (newInt,newState)<br />
<br />
</haskell><br />
<br />
So, we are creating an anonymous function that will take an initial<br />
state, 0, and return a "newInt" and "newState". <br />
<br />
To do that we need to unpack and run our "monad" against the<br />
initialState in order to get the "oldInt" and the "oldState".<br />
<br />
The "oldInt" will be passed to the "doNext" function (the next<br />
anonymous function in our do block) together with the "oldState" to<br />
get the "newInt" and the "newState".<br />
<br />
We can now declare our type "MS" as an instance of the Monad class:<br />
<haskell><br />
<br />
> instance Monad MS where<br />
> return a = mkMS a<br />
> (>>=) m f = bindMS m f<br />
<br />
</haskell><br />
<br />
We now need a function to increase the counter in our monad from<br />
within a do block:<br />
<br />
<haskell><br />
<br />
> incState :: MS ()<br />
> incState = MS (\s -> ((), s + 1))<br />
<br />
</haskell><br />
<br />
This is easier then it looks like. We use the type constructor MS to<br />
create a function that takes a state an returns a void integer ()<br />
paired with the state increased by one. We do not need any binding,<br />
since we are just modifying the state, an integer, and, in our do<br />
block, we will insert this function before a new line, so that the non<br />
binding ">>" operator will be applied.<br />
<br />
And now the evaluator:<br />
<br />
<haskell><br />
<br />
> evalMS :: Term -> MS Int<br />
> evalMS (Con a) = do incState<br />
> mkMS a<br />
> evalMS (Add t u) = do a <- evalMS t<br />
> b <- evalMS u<br />
> incState <br />
> return (a + b)<br />
<br />
</haskell><br />
<br />
Very easy: we just added the "incState" function before returning the<br />
sum of the evaluation of the Terms of our expression.<br />
<br />
Let's try it:<br />
<br />
*TheMonadicWay> unpackMSandRun (evalMS (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12))))) 0<br />
(54,7)<br />
*TheMonadicWay> <br />
<br />
As you can see, adding a counter makes our binding operations a bit<br />
more complicated by the fact that we have an anonymous function within<br />
our monad. This means that we must recreate that anonymous function in<br />
each step of our do block. This makes "incState" and, as we are going<br />
to see in the next paragraph, the function to produce output a bit<br />
more complicated. Anyway we can handle this complexity quite well, for<br />
now.<br />
<br />
===The monadic evaluator with output and counter in do-notation===<br />
<br />
Adding output to our evaluator is now quite easy. It's just a matter<br />
of adding a field to our type, where we are going to accumulate the<br />
output, and take care of extracting it in our bind function to<br />
concatenate the old one with the new one.<br />
<br />
<haskell><br />
<br />
> newtype Eval_SIO a = Eval_SIO { unPackMSIOandRun :: State -> (a, State, Output) }<br />
<br />
</haskell><br />
<br />
Now our monad contains an anonymous function that takes the initial<br />
state, 0, and will produce the final Integer, the final state and the<br />
concatenated output.<br />
<br />
So, this is bind:<br />
<br />
<haskell><br />
<br />
> bindMSIO monad doNext = <br />
> Eval_SIO (\initialState -><br />
> let (oldInt, oldState, oldOutput) = unPackMSIOandRun monad initialState in<br />
> let (newInt, newState, newOutput) = unPackMSIOandRun (doNext oldInt) oldState in<br />
> (newInt, newState, oldOutput ++ newOutput))<br />
<br />
</haskell><br />
<br />
And this is our "return":<br />
<haskell><br />
<br />
> mkMSIO int = Eval_SIO (\s -> (int, s, ""))<br />
<br />
</haskell><br />
<br />
Now we can declare our type, "Eval_SIO", as an instance of the Monad class:<br />
<br />
<haskell><br />
<br />
> instance Monad Eval_SIO where<br />
> return a = mkMSIO a<br />
> (>>=) m f = bindMSIO m f<br />
<br />
</haskell><br />
<br />
Now, the function to increment the counter will also insert an empty<br />
string "" in our monad: "bind" will take care of concatenating it with<br />
the old output:<br />
<br />
<haskell><br />
<br />
> incSIOstate :: Eval_SIO () <br />
> incSIOstate = Eval_SIO (\s -> ((), s + 1, ""))<br />
<br />
</haskell><br />
<br />
The function to insert some new output will just insert a string into<br />
our monad, together with a void Integer (). Since no binding will<br />
occur (>> will be applied), the () will not be taken into<br />
consideration within the anonymous functions automatically created for<br />
us within the do block:<br />
<br />
<haskell><br />
<br />
> print_SIO :: Output -> Eval_SIO ()<br />
> print_SIO x = Eval_SIO (\s -> ((),s, x))<br />
<br />
</haskell><br />
<br />
And now the evaluator, that puts everything together. As you can see<br />
it did not change too much from the previous versions:<br />
<br />
<haskell><br />
<br />
> eval_SIO :: Term -> Eval_SIO Int<br />
> eval_SIO (Con a) = do incSIOstate<br />
> print_SIO (formatLine (Con a) a)<br />
> return a<br />
> eval_SIO (Add t u) = do a <- eval_SIO t<br />
> b <- eval_SIO u<br />
> incSIOstate<br />
> print_SIO (formatLine (Add t u) (a + b))<br />
> return (a + b)<br />
<br />
</haskell><br />
<br />
Running it will require unpacking the monad and feeding it with the initial state 0:<br />
<br />
unPackMSIOandRun (eval_SIO (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12))))) 0<br />
*TheMonadicWay> unPackMSIOandRun (eval_SIO (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12))))) 0<br />
(54,7,"eval (Con 6) <= 6 - eval (Con 16) <= 16 - <br />
eval (Con 20) <= 20 - <br />
eval (Con 12) <= 12 - <br />
eval (Add (Con 20) (Con 12)) <= 32 - <br />
eval (Add (Con 16) (Add (Con 20) (Con 12))) <= 48 - <br />
eval (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <= 54 - ")<br />
*TheMonadicWay> <br />
<br />
(I formatted the output).<br />
<br />
<br />
==If there's a state we need some discipline: Dealing with complexity==<br />
<br />
'''(Text to be done yet: just a summary)'''<br />
<br />
In order to increase the complexity of our monad now we will try to<br />
mix State (counter), Exceptions and Output.<br />
<br />
This is an email [http://www.haskell.org/pipermail/haskell-cafe/2006-August/017672.html I send to the haskell-cafe mailing list]:<br />
<br />
<pre><br />
Now I'm trying to create a statefull evaluator, with output and<br />
exception, but I'm facing a problem I seem not to be able to<br />
conceptually solve.<br />
<br />
Take the code below.<br />
Now, in order to get it run (and try to debug) the Eval_SOI type has a<br />
Raise constructor that produces the same type of SOIE. Suppose instead it<br />
should be constructing something like Raise "something". <br />
Moreover, I wrote a second version of >>=, commented out.<br />
This is just to help me illustrate to problem I'm facing.<br />
<br />
Now, >>= is suppose to return Raise if "m" is matched against Raise<br />
(second version commented out).<br />
If "m" matches SOIE it must return a SOIE only if "f a" does not<br />
returns a Raise (output must be concatenated).<br />
<br />
I seem not to be able to find a way out. Moreover, I cannot understand<br />
if a way out can be possibly found. Something suggests me it could be<br />
related to that Raise "something".<br />
But my feeling is that functional programming could be something out<br />
of the reach of my mind... by the way, I teach Law, so perhaps you'll<br />
forgive me...;-)<br />
<br />
If you can help me to understand this problem all I can promise is<br />
that I'll mention your help in the tutorial I'm trying to write on<br />
"the monadic way"... that seems to lead me nowhere.<br />
<br />
Thanks for your kind attention.<br />
<br />
Andrea<br />
</pre><br />
<br />
This was the code:<br />
<br />
<haskell><br />
data Eval_SOI a = Raise { unPackMSOIandRun :: State -> (a, State, Output) }<br />
| SOIE { unPackMSOIandRun :: State -> (a, State, Output) }<br />
<br />
instance Monad Eval_SOI where<br />
return a = SOIE (\s -> (a, s, ""))<br />
m >>= f = SOIE (\x -><br />
let (a, y, s1) = unPackMSOIandRun m x in<br />
case f a of<br />
SOIE nextRun -> let (b, z, s2) = nextRun y in <br />
(b, z, s1 ++ s2)<br />
Raise e1 -> e1 y --only this happens<br />
<br />
)<br />
-- (>>=) m f = case m of<br />
-- Raise e -> error "ciao" -- why this is not going to happen?<br />
-- SOIE a -> SOIE (\x -><br />
-- let (a, y, s1) = unPackMSOIandRun m x in<br />
-- let (b, z, s2) = unPackMSOIandRun (f a) y in <br />
-- (b, z, s1 ++ s2)) <br />
<br />
<br />
incSOIstate :: Eval_SOI ()<br />
incSOIstate = SOIE (\s -> ((), s + 1, ""))<br />
<br />
print_SOI :: Output -> Eval_SOI ()<br />
print_SOI x = SOIE (\s -> ((),s, x))<br />
<br />
raise x e = Raise (\s -> (x,s,e))<br />
<br />
eval_SOI :: Term -> Eval_SOI Int<br />
eval_SOI (Con a) = do incSOIstate<br />
print_SOI (formatLine (Con a) a)<br />
return a<br />
eval_SOI (Add t u) = do a <- eval_SOI t<br />
b <- eval_SOI u<br />
incSOIstate<br />
print_SOI (formatLine (Add t u) (a + b))<br />
if (a + b) == 42 <br />
then raise (a+b) " = The Ultimate Answer!!"<br />
else return (a + b)<br />
<br />
runEval exp = case eval_SOI exp of<br />
Raise a -> a 0<br />
SOIE p -> let (result, state, output) = p 0 in<br />
(result,state,output)<br />
<br />
<br />
<br />
--runEval (Add (Con 10) (Add (Con 28) (Add (Con 40) (Con 2))))<br />
</haskell><br />
<br />
This code will produce <br />
<br />
eval (Con 10) <= 10 -<br />
eval (Con 28) <= 28 -<br />
eval (Con 40) <= 40 -<br />
eval (Con 2) <= 2 - = The Ultimate Answer!!<br />
eval (Add (Con 28) (Add (Con 40) (Con 2))) <= 70 -<br />
eval (Add (Con 10) (Add (Con 28) (Add (Con 40) (Con 2)))) <= 80 -<br />
<br />
The exception appears in the output, but executioon is not stopped.<br />
<br />
===Monadic evaluator with output, counter and exception, in do-notation===<br />
<br />
Brian Hulley [http://www.haskell.org/pipermail/haskell-cafe/2006-August/017680.html came up with this solution]:<br />
<br />
<haskell><br />
<br />
> -- thanks to Brian Hulley<br />
> data Result a<br />
> = Good a State Output<br />
> | Bad State Output Exception<br />
> deriving Show<br />
<br />
> newtype Eval_SIOE a = SIOE {runSIOE :: State -> Result a}<br />
<br />
> instance Monad Eval_SIOE where<br />
> return a = SIOE (\s -> Good a s "")<br />
> m >>= f = SIOE $ \x -><br />
> case runSIOE m x of<br />
> Good a y o1 -><br />
> case runSIOE (f a) y of<br />
> Good b z o2 -> Good b z (o1 ++ o2)<br />
> Bad z o2 e -> Bad z (o1 ++ o2) e<br />
> Bad z o2 e -> Bad z o2 e<br />
<br />
> raise_SIOE e = SIOE (\s -> Bad s "" e)<br />
<br />
> incSIOEstate :: Eval_SIOE ()<br />
> incSIOEstate = SIOE (\s -> Good () (s + 1) "")<br />
<br />
> print_SIOE :: Output -> Eval_SIOE ()<br />
> print_SIOE x = SIOE (\s -> Good () s x)<br />
<br />
<br />
> eval_SIOE :: Term -> Eval_SIOE Int<br />
> eval_SIOE (Con a) = do incSIOEstate<br />
> print_SIOE (formatLine (Con a) a)<br />
> return a<br />
> eval_SIOE (Add t u) = do a <- eval_SIOE t<br />
> b <- eval_SIOE u<br />
> incSIOEstate<br />
> let out = formatLine (Add t u) (a + b)<br />
> print_SIOE out<br />
> if (a+b) == 42<br />
> then raise_SIOE $ out ++ "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
> runEval exp = case runSIOE (eval_SIOE exp) 0 of<br />
> Bad s o e -> "Error at iteration n. " ++ show s ++ <br />
> " - Output stack = " ++ o ++ <br />
> " - Exception = " ++ e<br />
> Good a s o -> "Result = " ++ show a ++ <br />
> " - Iterations = " ++ show s ++ " - Output = " ++ o<br />
<br />
</haskell><br />
<br />
Run with runEval (Add (Con 18) (Add (Con 12) (Add (Con 10) (Con 2))))<br />
<br />
==Suggested readings==<br />
<br />
:Cale Gibbard, [[Monads as containers]]<br />
:Jeff Newbern, [http://haskell.org/all_about_monads/html/contmonad.html All About Monads]<br />
:[[IO inside]]<br />
:[http://sigfpe.blogspot.com/2006/08/you-could-have-invented-monads-and.html You Could Have Invented Monads! (And Maybe You Already Have.) by sigfpe]<br />
<br />
<br />
==Acknowledgments==<br />
<br />
Thanks to Neil Mitchell, Daniel Fisher, Bulat Ziganzhin, Brian Hulley<br />
and Udo Stenzel for the invaluable help they gave, in the<br />
[http://www.haskell.org/mailman/listinfo/haskell-cafe haskell-cafe mailing list], <br />
in understanding this topic.<br />
<br />
I couldn't do it without their help.<br />
<br />
Obviously errors are totally mine. But this is a wiki so, please,<br />
correct them!<br />
<br />
- [[User:AndreaRossato|Andrea Rossato]]<br />
<br />
[[Category:Tutorials]]<br />
[[Category:Monad]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=The_Monadic_Way/Part_I&diff=14663The Monadic Way/Part I2007-07-24T22:45:28Z<p>BrettGiles: /* An evaluation of Philip Wadler's "Monads for functional programming" */ links, grammar</p>
<hr />
<div>'''Note: this is the first part of [[The Monadic Way]]'''<br />
==An evaluation of Philip Wadler's "Monads for functional programming"==<br />
<br />
This tutorial is a "translation" of Philip Wadler's [http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf "Monads for functional programming"].<br />
(avail. from [http://homepages.inf.ed.ac.uk/wadler/topics/monads.html here])<br />
<br />
I'm a Haskell newbie trying to grasp such a difficult concept as the<br />
one of Monad and monadic computation.<br />
<br />
While [http://www.cs.utah.edu/~hal/htut/ "Yet Another Haskell Tutorial"] <br />
gave me a good understanding of the [[type]] system when it<br />
comes to monads I find it almost unreadable.<br />
<br />
But I had also Wadler's paper, and started reading it. Well, just<br />
wonderful! It explains how to ''create'' a monad!<br />
<br />
So I decided to "translate it", in order to clarify to myself the<br />
topic. And I'm now sharing this translation ('''not completed yet'')<br />
with the hope it will be useful to someone else.<br />
<br />
Moreover, this is a wiki, so please improve it. Specifically, please<br />
correct my poor English. I'm Italian, after all.<br />
<br />
'''Note: The source of this page can be used as a [[Literate programming|literate Haskell]] file and can be run with [[GHC/GHCi|ghci]] or [[hugs]]: So cut paste change and run (in [[Haskell mode for Emacs |emacs]] for instance) while reading it...'''<br />
<br />
==A simple evaluator==<br />
<br />
Let's start with something simple: suppose we want to implement a new<br />
programming language. We just finished with<br />
[http://swiss.csail.mit.edu/classes/6.001/abelson-sussman-lectures/ Abelson and Sussman's Structure and Interpretation of Computer Programs] <br />
and we want to test what we have learned.<br />
<br />
Our programming language will be very simple: it will just compute the<br />
sum of two terms.<br />
<br />
So we have just one primitive operation (Add) that takes two constants<br />
and calculates their sum.<br />
<br />
Moreover we have just one kind of data type: Con a, which is an Int.<br />
<br />
For instance, something like:<br />
<br />
(Add (Con 5) (Con 6))<br />
<br />
should yield:<br />
<br />
11<br />
<br />
===The basic evaluator===<br />
<br />
We will implement our language with the help of a data type<br />
constructor such as:<br />
<br />
<div id="BasicEval"><br />
<haskell><br />
<br />
> module TheMonadicWay where<br />
> data Term = Con Int<br />
> | Add Term Term<br />
> deriving (Show)<br />
<br />
</haskell><br />
<br />
After that we build our interpreter:<br />
<br />
<haskell><br />
<br />
> eval :: Term -> Int<br />
> eval (Con a) = a<br />
> eval (Add a b) = eval a + eval b<br />
<br />
</haskell><br />
<br />
That's it. Just an example:<br />
<br />
*TheMonadicWay> eval (Add (Con 5) (Con 6))<br />
11<br />
*TheMonadicWay><br />
<br />
Very very simple. The evaluator checks if its argument is of type Con<br />
Int: if it is it just returns the Int.<br />
<br />
If the argument is not of type Con, but it is of type Term, it<br />
evaluates the first Term and sums the result with the result of the<br />
evaluation of the second Term.<br />
<br />
As you may understand, our evaluator uses some of the powerful<br />
features of Haskell type system. Instead of writing a parser that<br />
takes a string (the user input) and transforms that string into an<br />
expression to be evaluated, we use the two type constructors defined<br />
for our data type Term (Con and Add) to build the expression - such as<br />
(Add (Con 5) (Con 6)) - and to match the expression's elements in our<br />
"eval" function.<br />
<br />
<br />
== Some output, please!==<br />
<br />
Now, that's fine, but we'd like to add some features, like providing<br />
some output, to show how the computation was carried out.<br />
<br />
Well, but Haskell is a pure functional language, with no side effects,<br />
we were told.<br />
<br />
Now we seem to be wanting to create a side effect of the computation,<br />
its output, and be able to stare at it...<br />
<br />
If we had some global variable to store the out that would be<br />
simple...<br />
<br />
But we can create the output and carry it along the computation,<br />
concatenating it with the old one, and present it at the end of the<br />
evaluation together with the evaluation of the expression given to our<br />
evaluator/interpreter!<br />
<br />
===The basic evaluator with output===<br />
<br />
Simple and neat:<br />
<div id="BasivEvalO"><br />
<haskell><br />
<br />
> type MOut a = (a, Output)<br />
> type Output = String<br />
> <br />
> formatLine :: Term -> Int -> Output<br />
> formatLine t a = "eval (" ++ show t ++ ") <= " ++ show a ++ " - " <br />
> <br />
> evalO :: Term -> MOut Int<br />
> evalO (Con a) = (a, formatLine (Con a) a)<br />
> evalO (Add t u) = ((a + b),(x ++ y ++ formatLine (Add t u) (a + b)))<br />
> where (a, x) = evalO t<br />
> (b, y) = evalO u<br />
<br />
</haskell><br />
<br />
Now we have what we want. But we had to change our evaluator quite a<br />
bit. <br />
<br />
First we added a function, formatLine, that takes an argument of type<br />
Term (the expression to be evaluated), one of type Int (the result of<br />
the evaluation of Term) and gives back an output of type Output (that<br />
is a synonymous of String). This is just a helper function to format<br />
the string to output. Not very interesting at all.<br />
<br />
The evaluator itself changed quite a lot! Now it has a different type<br />
signature: it takes an argument of type Term and produces a new type,<br />
we called it MOut, that is actually a compound pair of a variable type<br />
a (an Int in our evaluator) and a type Output, a string.<br />
<br />
So our evaluator, now, will take a Term (the type of the expressions<br />
in our new programming language) and will produce a pair, composed of<br />
the result of the evaluation (an Int) and the Output, a string.<br />
<br />
So far so good. But what's happening inside the evaluator?<br />
<br />
The first part will just return a pair with the number evaluated ("a")<br />
and the output formatted by formatLine.<br />
<br />
The second part does something more complicated: it returns a pair<br />
composed by <br />
1. the result of the evaluation of the right Term summed to the result<br />
of the evaluation of the second Term<br />
2. the output: the concatenation of the output produced by the<br />
evaluation of the right Term, the output produced by the evaluation of<br />
the left Term (each this evaluation returns a pair with the number and<br />
the output), and the formatted output of the evaluation.<br />
<br />
Let's try it:<br />
*TheMonadicWay> evalO (Add (Con 5) (Con 6))<br />
(11,"eval (Con 5) <= 5 - eval (Con 6) <= 6 - eval (Add (Con 5) (Con 6)) <= 11 - ")<br />
*TheMonadicWay><br />
<br />
It works! Let's put the output this way:<br />
eval (Con 5) <= 5 - <br />
eval (Con 6) <= 6 - <br />
eval (Add (Con 5) (Con 6)) <= 11 -<br />
<br />
Great! We are able to produce a side effect of our evaluation and<br />
present it at the end of the computation, after all.<br />
<br />
Let's have a closer look at this expression:<br />
<haskell><br />
<br />
evalO (Add t u) = ((a + b),(x ++ y ++ formatLine (Add t u) (a + b)))<br />
where (a, x) = evalO t<br />
(b, y) = evalO u<br />
<br />
</haskell><br />
<br />
Why all that? The problem is that we need:<br />
* "a" and "b" to calculate their sum (a + b), that will be the first element of the compund pair rapresenting the type (MOut) our evaluator will return <br />
* "x and "y" (the output of each evaluation) to be concatenated with the ourput of formatLine by the expression (x ++ y ++ formatLine(...)): this will be the second element of the compound pair MOut, the string part.<br />
<br />
So we need to separate the pairs produced by "evalO t" and "evalO u".<br />
<br />
We do that within the where clause (remember: evalO now produces a value of type<br />
MOut Int, i.e. a pair of an Int and a String).<br />
<br />
Then we use the single element, "extraded" within the where clause, to<br />
return a new MOut composed by <br />
<br />
((a + b),(x ++ y ++ formatLine (Add t u) (a + b))).<br />
------ -------------------------------------<br />
Int Output = String<br />
<br />
== Let's go monadic==<br />
<br />
Is there a more general way of doing so?<br />
<br />
Let's analyze the evaluator from another perspective. From the type<br />
perspective.<br />
<br />
We solved our problem by creating a new type, a pair of an Int (the<br />
result of the evaluation) and a String (the output of the process of<br />
evaluation).<br />
<br />
The first part of the evaluator does nothing else but creating, from a<br />
value of type Int, an object of type MOut Int (Int,Output). It does so<br />
by creating a pair with that Int and some text produced by formatLine.<br />
<br />
The second part evaluates the two Term(s) and "stores" the values thus<br />
produced in some variables to be use later to compute the output.<br />
<br />
Let's focus on the "stores" action. The correct term should be<br />
"binds".<br />
<br />
Take a function:<br />
<haskell><br />
f x = x + x<br />
</haskell><br />
"x" appears on both sides of the expression. We say that on the right<br />
side "x" is bound to the value of x given on the left side.<br />
<br />
So<br />
<haskell><br />
f 3<br />
</haskell><br />
binds x to 3 for the evaluation of the expression "x + x".<br />
<br />
Our evaluator binds "a" and "x" / "b" and "y" with the evaluation of<br />
"evalO t" and "evalO u" respectively. <br />
<br />
Then "a","b","x" and "y" will be used in the evaluation of<br />
((a+b),(x++y++formatLine)), that will produce a value of type MOut Int:<br />
<br />
<pre><br />
<br />
((a + b),(x ++ y ++ formatLine (Add t u) (a + b))).<br />
------ -------------------------------------<br />
\ / \ /<br />
Int Output = String<br />
---------------------------------<br />
\ /<br />
MOut Int <br />
</pre><br />
<br />
The binding happens in the "where" clause:<br />
<haskell><br />
where (a, x) = evalO t<br />
(b, y) = evalO u<br />
</haskell><br />
<br />
We know that there is an ad hoc operator for binding variables to a<br />
value: lambda, or \.<br />
<br />
Indeed f x = x + x is syntactic sugar for:<br />
<haskell><br />
f = \x -> x + x<br />
</haskell><br />
When we write f 3 we are actually binding "x" to 3 within what's next<br />
"->", that will be used (substituted) for evaluating f 3.<br />
<br />
So we can try to abstract this phenomenon.<br />
<br />
===Monadic evaluator with output===<br />
What we need is a function that takes our composed type MOut Int and a<br />
function in order to produce a new MOut Int, concatenating the<br />
output of the computation of the first with the output of the<br />
computation of the second.<br />
<br />
This is what bindM does:<br />
<br />
<haskell><br />
<br />
> bindM :: MOut a -> (a -> MOut b) -> MOut b<br />
> bindM m f = (b, x ++ y)<br />
> where (a, x) = m<br />
> (b, y) = f a<br />
<br />
</haskell><br />
<br />
It takes:<br />
* "m": the compound type MOut Int carrying the result of an "eval Term",<br />
* a function "f". This function will take the Int ("a") extracted by the evaluation of "m" ((a,x)=m). This function will produce a new pair: a new Int produced by a new evaluation; some new output.<br />
<br />
bindM will return the new Int in pair with the concatenated outputs<br />
resulting from the evaluation of "m" and "f a".<br />
<br />
As you see, we took the binding part out from evalO and put it in this new function.<br />
<br />
So let's write the new version of the evaluator, that we will call evalM_1:<br />
<br />
<haskell><br />
<br />
> evalM_1 :: Term -> MOut Int<br />
> evalM_1 (Con a) = (a, formatLine (Con a) a)<br />
> evalM_1 (Add t u) = bindM (evalM_1 t) (\a -> <br />
> bindM (evalM_1 u) (\b -> <br />
> ((a + b), formatLine (Add t u) (a + b))<br />
> )<br />
> )<br />
<br />
</haskell><br />
<br />
Ugly, isn't it?<br />
<br />
Let's start from the outside:<br />
<br />
<haskell><br />
bindM (evalM_1 u) (\b -> ((a + b), formatLine (Add t u) (a + b)))<br />
</haskell><br />
<br />
bindM takes the result of the evaluation "evalM_1 u", a type Mout Int,<br />
and a function. It will extract the Int from that type and use it to<br />
bind "b".<br />
<br />
So in bindM (evalM_1 u) (\b ->) "b" will be bound to the value<br />
returned by evalM_1 u, and this bound variable will be available in<br />
what comes after "->" as a bound variable (not free).<br />
<br />
Then the outer part (bindM (evalM_1 t) (\a...) will bind "a" to the<br />
value returned "evalM_1 t", the result of the evaluatuion of the first<br />
Term. This value is needed to evaluate "((a+b), formatLine...) and<br />
produce our final MOut Int.<br />
<br />
We can try to explain "bindM" in a different way by using more descriptive names.<br />
<br />
As we have seen, "bindM" extracts the Int part from our type. The Int<br />
part will be used for further computations and the Output part will be<br />
concatenated. As a result we will have a new pair with a new Int and<br />
an accumulated Output.<br />
<br />
The new version of "bindM":<br />
<haskell><br />
<br />
> getIntFromType typeMOut doSomething = (newInt,oldOutput ++ newOutput)<br />
> where (oldInt,oldOutput) = typeMOut<br />
> (newInt,newOutput) = (doSomething oldInt)<br />
<br />
</haskell><br />
<br />
As you can see it does the very same things that "bindM" does: it<br />
takes something of type MOut and a function to perform some<br />
computation with the Int part. <br />
<br />
In the "where" clause, the old Int and the old output<br />
will be extracted from our type MOut (first line of the "where"<br />
clause). <br />
<br />
A new Int and a new output will be extracted from evaluating<br />
(doSomething oldInt) in the second line.<br />
<br />
Our function will return the new Int and the concatenated outputs.<br />
<br />
We do not need to define our doSomething function, because it will be<br />
an anonymous function:<br />
<br />
<haskell><br />
<br />
> evaluator (Con a) = (a, "output-")<br />
> evaluator (Add t u) = <br />
> getIntFromType (evaluator t) <br />
> (\firstInt -> getIntFromType (evaluator u) <br />
> (\secondInt -> ((firstInt + secondInt),("-newoutput"))))<br />
<br />
</haskell><br />
<br />
As you can see we are feeding our "getIntFromType" with the evaluation<br />
of an expression ("evaluator t" and "evaluator u"). The second<br />
argument of "getIntFromType" is an anonymous function that takes the<br />
"oldInt" and does something with it.<br />
<br />
So we have a series of nested anonymous functions. Their arguments<br />
("\firstInt" and "\secondInt") will be used to produce the computation<br />
we need ("(firstInt + secondInt). Moreover "getIntFromType" will take<br />
care of concatenating the outputs.<br />
<br />
This is the result:<br />
<br />
*TheMonadicWay> evaluator (Add (Con 5) (Con 6))<br />
(11,"output-output--newoutput")<br />
*TheMonadicWay> <br />
<br />
Going back to our "bindM", we can now use lambda notation to write our<br />
evaluator in a more convinient way:<br />
<br />
<haskell><br />
<br />
> evalM_2 :: Term -> MOut Int<br />
> evalM_2 (Con a) = (a, formatLine (Con a) a)<br />
> evalM_2 (Add t u) = evalM_2 t `bindM` \a -><br />
> evalM_2 u `bindM` \b -><br />
> ((a + b), (formatLine (Add t u) (a + b)))<br />
<br />
</haskell><br />
<br />
Now, look at the first part:<br />
<br />
<haskell><br />
evalM_2 (Con a) = (a, formatLine (Con a) a)<br />
</haskell><br />
<br />
We could use a more general way of creating some output. <br />
<br />
We can create a function that takes an Int and returns the type MOut<br />
Int. We do that by pairing the received Int with an empty string "".<br />
<br />
This will be a general way of creating an object with type MOut Int starting from an Int.<br />
<br />
Or, more generaly, a function that takes something of a variable type<br />
a, and return an object of type MOut a, a coumpunt object made up of<br />
an element of type a, and one of type String.<br />
<br />
There it is:<br />
<br />
<haskell><br />
<br />
> mkM :: a -> MOut a<br />
> mkM a = (a, "")<br />
<br />
</haskell><br />
<br />
As you can see, this function will just push an Int and an empty<br />
string ("") inside our type MOut.<br />
<br />
Then we need a method of inserting some text in our object of type<br />
MOut. So we will take a string and return it paired with a void<br />
element "()":<br />
<br />
<haskell><br />
<br />
> outPut :: Output -> MOut ()<br />
> outPut x = ((), x)<br />
<br />
</haskell><br />
<br />
Very simple: we have a string "x" (Output) and create a pair with a ()<br />
instead of an Int, and the output.<br />
<br />
You can see this function as one that pushes a string, paired with a<br />
void int, inside our type MOut.<br />
<br />
Now we can rewrite:<br />
<haskell><br />
evalM_2 (Con a) = (a, formatLine (Con a) a)<br />
</haskell><br />
using the bindM function:<br />
<haskell><br />
evalM_2 (Con a) = outPut (formatLine (Con a) a) `bindM` \_ -> mkM a<br />
</haskell><br />
<br />
First we create an object of type MOut with the Int part (). As you<br />
see bindM will not use it ("\_"), but will concatenate the String part<br />
with the result of mkM, which in turn is the empty string "".<br />
<br />
In other words, first we insert the Output part (a string) in our<br />
MOut, and then we insert the Int paired with an empty string: "bindM"<br />
will not use the void int (the anonymous function will not use it's<br />
argument: "\_"), but will take care of concatenating the non empty<br />
string inserted by "outPut" with the empty one inserted by "mkM".<br />
<br />
Let's rewrite the evaluator:<br />
<br />
<haskell><br />
<br />
> evalM_3 :: Term -> MOut Int<br />
> evalM_3 (Con a) = outPut (formatLine (Con a) a) `bindM` \_ -> <br />
> mkM a<br />
> evalM_3 (Add t u) = evalM_3 t `bindM` \a -><br />
> evalM_3 u `bindM` \b -><br />
> outPut (formatLine (Add t u) (a + b)) `bindM` \_ -> <br />
> mkM (a + b)<br />
<br />
</haskell><br />
<br />
Well, this is fine, definetly better then before, anyway.<br />
<br />
Still we use `bindM` \_ -> that binds something we do not use (_). We<br />
could write a function for this specific case, when we concatenate<br />
computations without the need of binding variables for later uses.<br />
Let's call it `combineM`:<br />
<br />
<haskell><br />
<br />
> combineM :: MOut a -> MOut b -> MOut b<br />
> combineM m f = m `bindM` \_ -> f<br />
<br />
</haskell><br />
<br />
This is just something that will allow us to write the evaluator in a<br />
more concise way. <br />
<br />
So the new evaluator:<br />
<br />
<haskell><br />
<br />
> evalM :: Term -> MOut Int<br />
> evalM (Con a) = outPut (formatLine (Con a) a) `combineM` <br />
> mkM a<br />
> evalM (Add t u) = evalM t `bindM` \a -><br />
> evalM u `bindM` \b -><br />
> outPut (formatLine (Add t u) (a + b)) `combineM` <br />
> mkM (a + b)<br />
<br />
</haskell><br />
<br />
Let's put everything together (changing M into MO, so that this file<br />
will be still usable as a Literate Haskell file):<br />
<br />
<haskell><br />
<br />
> type MO a = (a, Out)<br />
> type Out = String<br />
<br />
> mkMO :: a -> MO a<br />
> mkMO a = (a, "")<br />
<br />
> bindMO :: MO a -> (a -> MO b) -> MO b<br />
> bindMO m f = (b, x ++ y)<br />
> where (a, x) = m<br />
> (b, y) = f a<br />
<br />
> combineMO :: MO a -> MO b -> MO b<br />
> combineMO m f = m `bindM` \_ -> f<br />
<br />
> outMO :: Out -> MO ()<br />
> outMO x = ((), x)<br />
<br />
> evalMO :: Term -> MO Int<br />
> evalMO (Con a) = outMO (formatLine (Con a) a) `combineMO`<br />
> mkMO a<br />
> evalMO (Add t u) = evalMO t `bindMO` \a -><br />
> evalMO u `bindMO` \b -><br />
> outMO (formatLine (Add t u) (a + b)) `combineMO` <br />
> mkMO (a + b)<br />
<br />
</haskell><br />
<br />
==What does bind bind?==<br />
<br />
<div id="Bind"><br />
The evaluator looks like:<br />
<haskell><br />
evalM t >>= \a -> evalM u >>= \b -> outPut "something" >>= \_ -> mkM (a +b)<br />
</haskell><br />
where >>= is bindMO, obviously.<br />
<br />
Let's do some substitution, writing the type of their output of each function:<br />
* evalMO t => (a,Out) - where a is Int<br />
* evalMO u => (b,Out) - where b is the same of a, an Int, but with a different value<br />
* outMO Out = ((),Out)<br />
* mkMO (a+b) => ((a+b),Out) - where (a+b) is the same of a and b, but with a different value from either a and b<br />
<br />
<pre><br />
B | (a,Out) >>= \a -> (b,Out) >>= \b -> ((),Out) >>= \_ >>= ((a + b), Out)---\<br />
i | V V V V V V V V ^ ^ ^ ^ |\<br />
n | |__|________^ | | ^ | | | | | | | MOut Int <=> ((a+b), Out)<br />
d |_____|__(++)__|_Out_|__|__(++)__V_Out_|___|___(++)_|_(++)__|___|____|_____|/<br />
i | | |______(b)__|_____|_____(b)____|__(b)__|___|<br />
n | |_________(a)___________|____________|__(a)__|<br />
g | |_____()_____|<br />
<br />
</pre><br />
<br />
Clear, isn't it?<br />
<br />
"bindMO" is just a function that takes care of gluing together, inside<br />
a data type, a sequence of computations!<br />
<br />
== Some sugar, please!==<br />
Now our evaluator has been completely transformed into a monadic<br />
evaluator. That's what it is: a monad.<br />
<br />
We have a function that constructs an object of type MO Int, formed by<br />
a pair: the result of the evaluation and the accumulated<br />
(concatenated) output.<br />
<br />
The process of accumulation and the act of parting the MO Int into its<br />
component is buried into bindMO, now, that can also preserve some<br />
value for later uses.<br />
<br />
So we have:<br />
* MO a type constructor for a type carrying a pair composed by an Int and a String;<br />
* bindMO, that gives a direction to the process of evaluation: it concatenates computations and captures some side effects we created (the direction is given by the changes in the Out part: there's a "before" when Out was something and there's a "later" when Out is something else).<br />
* mkMO lets us create an object of type MO Int starting from an Int.<br />
<br />
As you see this is all we need to create a monad. In other words<br />
monads arise from the type system and the lambda calculus. Everything<br />
else is just syntactic sugar.<br />
<br />
So, let's have a look at that sugar: the famous do-notation!<br />
<br />
===Monadic evaluator with output in do-notation===<br />
<br />
In order to be able to use the "do-notation" we need to define a new<br />
type and make it an instance of the Monad class. To make a new type an<br />
instance of the Monad class we will have to define the two methods of<br />
this class: (>>=) and "return".<br />
<br />
This is not going to be difficult, because we already created these<br />
two methods: "bindM" and "mkM". Now we will have to rewrite them in<br />
order to reflect the fact that we are not going to use a type, for our<br />
evaluator, that is a synonymous of other types, as we did before.<br />
Indeed our MOut was defined with the "type" keyword. Now we will have<br />
to define a "real" new type with either "newtype" or "data". Since we<br />
are not going to need multiple constructors, we will use "newtype".<br />
<br />
<div id="MonadicEvalIO"><br />
<haskell><br />
<br />
> newtype Eval_IO a = Eval_IO (a, O)<br />
> deriving (Show)<br />
> type O = String<br />
<br />
</haskell><br />
<br />
This is our new type: it will have a single type constructor, whose<br />
name is the same of the type name ("Eval_IO"). The type constructor<br />
takes a parameter ("a"), a variable type, and will build a type formed<br />
by a type "a" (an Int in our case) and a String (O is indeed<br />
synonymous of String).<br />
<br />
We now need to define our "bind" function to reflect the fact that we<br />
are now using a "real" type, and, to unpack its content, we need to do<br />
pattern-matching we the type constructor "Eval_IO". Moreover, since we<br />
must return an Eval_IO type, we will use the type constructor also for<br />
building the new type with the new int and the concatenated output.<br />
<br />
For the rest our "bind" function will be identical to the one we<br />
defined before.<br />
<br />
We are going to use very descriptive names:<br />
<br />
<haskell><br />
<br />
> getInt monad doSomething = Eval_IO (newInt,oldOutput ++ newOutput)<br />
> where Eval_IO (oldInt,oldOutput) = monad<br />
> Eval_IO (newInt,newOutput) = (doSomething oldInt)<br />
<br />
</haskell><br />
<br />
As you can see, we are using Eval_IO to build the result of the<br />
computation to be returned by getInt: "Eval_IO (newInt,oldOutput ++<br />
newOutput)". And we are using it to match the internal components of<br />
our type in the "where" clause.<br />
<br />
We also need to create a function that, like mkO, will take an Int and,<br />
using the type constructor "Eval_IO", will create an object of type<br />
Eval_IO with that Int and an empty string:<br />
<br />
<haskell><br />
<br />
> createEval_IO :: a -> Eval_IO a<br />
> createEval_IO int = Eval_IO (int,"")<br />
<br />
</haskell><br />
<br />
And, finally, we need a function that will insert, in our type, a<br />
string and a void ():<br />
<br />
<haskell><br />
<br />
> print_IO :: O -> Eval_IO ()<br />
> print_IO string = Eval_IO ((), string)<br />
<br />
</haskell> <br />
<br />
With these functions we could write our monadic evaluator without the<br />
"do-notation" like this:<br />
<br />
<haskell><br />
<br />
> evalM_4 :: Term -> Eval_IO Int<br />
> evalM_4 (Con a) = createEval_IO a<br />
> evalM_4 (Add t u) = evalM_4 t `getInt` \a -><br />
> evalM_4 u `getInt` \b -><br />
> print_IO (formatLine (Add t u) (a + b)) `getInt` \_ -><br />
> createEval_IO (a + b)<br />
<br />
</haskell><br />
<br />
It is very similar to the previous evaluator, as you can see. The only<br />
differences are related to the fact that we are now using a "real"<br />
type and not a type synonymous: this requires the use of the type<br />
constructor to match the type and its internal part (as we do in the<br />
"where" clause of our "bind" function: "getInt") or to build the type<br />
(as we do in the "bind" function to return the new Int with the<br />
concatenated output).<br />
<br />
Running this evaluator will produce:<br />
<br />
*TheMonadicWay> evalM_4 (Add (Con 6) (Con 12))<br />
Eval_IO (18,"eval (Add (Con 6) (Con 12)) <= 18 - ")<br />
*TheMonadicWay> <br />
<br />
Now we have everything we need to declare our type, Eval_IO, as an<br />
instance of the Monad class:<br />
<haskell><br />
<br />
> instance Monad Eval_IO where<br />
> return a = createEval_IO a<br />
> (>>=) m f = getInt m f<br />
<br />
</haskell><br />
<br />
As you see we are just using our defined functions as methods for our<br />
instance of the Monad class.<br />
<br />
This is all we need to do. Notice that we do not have to define the<br />
"combineM" function, for chaining computation, as we do with "getInt",<br />
without binding variables for later use within the series of nested<br />
anonymous functions (the "doSomething" part) that will form the "do"<br />
block.<br />
<br />
This function comes for free by just defining our type as an instance<br />
of the Monad class. Indeed, if you look at the definition of the Monad<br />
class in the Prelude you see that "combineM", or (>>) is deduced by<br />
the definition of (>>=):<br />
<br />
<haskell><br />
class Monad m where<br />
return :: a -> m a<br />
(>>=) :: m a -> (a -> m b) -> m b<br />
(>>) :: m a -> m b -> m b<br />
fail :: String -> m a<br />
<br />
-- Minimal complete definition: (>>=), return<br />
p >> q = p >>= \ _ -> q<br />
fail s = error s<br />
</haskell><br />
<br />
You can see that the "combineM"" method (or (>>)) is automatically<br />
derived by the "bindMO" (or >>=) method:<br />
<br />
<haskell><br />
p >> q = p >>= \ _ -> q<br />
</haskell><br />
<br />
We can now write our evaluator using the do-notation:<br />
<br />
<haskell><br />
<br />
> eval_IO :: Term -> Eval_IO Int<br />
> eval_IO (Con a) = do print_IO (formatLine (Con a) a)<br />
> return a<br />
> eval_IO (Add t u) = do a <- eval_IO t<br />
> b <- eval_IO u<br />
> print_IO (formatLine (Add t u) (a + b))<br />
> return (a + b)<br />
<br />
</haskell><br />
<br />
As you can see the anonymous functions are gone. Instead we use this:<br />
a <- eval_IO t<br />
<br />
This seems like an assignment, that cannot be possible in Haskell. In<br />
fact it is just the way our anonymous function's arguments is bound<br />
within a do block.<br />
<br />
Even if it does not seem like a series of nested anonymous functions,<br />
this is what actually a do block is.<br />
<br />
Our monad is defined by three elements: <br />
* a type, with its type constructor(s);<br />
* a bind method: it will bind an unwritten anonymous function's argument to the value of the Int part of our type, or more generally, of the variable type "a". It will also create a series of anonymous functions: a line for each function;<br />
* a "return" function, to insert, into out type, a value of type Int, or, more generally, a value of variable type "a".<br />
<br />
Additionally, we need a function to insert a string in our type,<br />
string that the derived "bind" (>>) will concatenate ignoring the void<br />
(), our "print_IO".<br />
<br />
Within a do block we can thus perform only tree kinds of operations:<br />
* a computation that produces a new Int, packed inside our monad's type, to be extracted and bound to a variable (an anonymous function's argument really):<br />
** this operation requires a binding (">>= \varName ->"), translated into "varName <- computation"<br />
** example: a <- eval_IO t<br />
* a computation that inserts a string into our monad, a string to be concatenated, without the need of binding a variable (an anonymous function's argument really):<br />
** this operation does not require a binding: it will be ">>= \_ ->", i.e. ">>", translated into a simple new line<br />
** example: print_IO (formatLine (Add t u) (a + b))<br />
* a computation that inserts an Int into our monad without the need of binding a variable (an anonymous function's argument really):<br />
** this operation is carried out by the <hask>return</hask> method (usually at the end of a do block, useless in the middle)<br />
** example <hask>return (a + b)</hask><br />
<br />
To sum up, within a block, "do" will take care of creating and<br />
nesting, for us, all the needed anonymous functions so that bound<br />
variables will be available for later computations.<br />
<br />
In this way we can emulate a direction of our computation, a "before"<br />
and an "after", even within a pure functional language. And we can use<br />
this possibility to create and accumulate side effects, like output.<br />
<br />
Let's see the evaluator with output in action:<br />
*TheMonadicWay> eval_IO (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <br />
Eval_IO (54,"eval (Con 6) <= 6 - eval (Con 16) <= 16 - eval (Con 20) <= 20 - eval (Con 12) <= 12 - \<br />
eval (Add (Con 20) (Con 12)) <= 32 - eval (Add (Con 16) (Add (Con 20) (Con 12))) <= 48 - \<br />
eval (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <= 54 - ")<br />
*TheMonadicWay> <br />
<br />
Let's format the output part:<br />
eval (Con 6) <= 6 <br />
eval (Con 16) <= 16 <br />
eval (Con 20) <= 20 <br />
eval (Con 12) <= 12 <br />
eval (Add (Con 20) (Con 12)) <= 32 <br />
eval (Add (Con 16) (Add (Con 20) (Con 12))) <= 48 <br />
eval (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <= 54 <br />
<br />
==[[Type]] and [[Newtype]]: What happened to our output?==<br />
<br />
Well, actually something happened to the output. Let's compare the<br />
output of evalMO (the monadic evaluator written without the<br />
do-notation) and eval_IO:<br />
<br />
*TheMonadicWay> evalMO (Con 6)<br />
(6,"eval (Con 6) <= 6 - ")<br />
*TheMonadicWay> eval_IO (Con 6)<br />
Eval_IO (6,"eval (Con 6) <= 6 - ")<br />
*TheMonadicWay> <br />
<br />
They look almost the same, but they are not the same: the output of<br />
eval_IO has the Eval_IO stuff. It must be related to the changes we<br />
had to do to our evaluator in order to use the do-conation, obviously.<br />
<br />
We can now review some of our basic knowledge of Haskell's type<br />
system.<br />
<br />
What's changed? First the type definition. We have now:<br />
<br />
<haskell><br />
newtype Eval_IO a = Eval_IO (a, O)<br />
deriving (Show)<br />
</haskell><br />
<br />
instead of <br />
<br />
<haskell><br />
type MO a = (a, Out)<br />
</haskell><br />
<br />
Now <hask>return a</hask> is the product of the application of the<br />
type constructor Eval_IO to the pair that are going to form our monad.<br />
<br />
"return" takes an Int and inserts it into our monad. It will also<br />
insert an empty String "" that (>>=) or (>>) will then concatenate in<br />
the sequence of computations they glue together.<br />
<br />
The same for (>>=). It will now return something constructed by<br />
Eval_IO: <br />
<br />
* "newInt", the result of the application of "doSomething" to "oldInt" (better, the binding of "oldInt" in "doSomething");<br />
* the concatenation of "oldOutput" (matched by <hask>Eval_IO (oldInt, oldOutput)</hask> with the evaluation of "monad" - "eval_IO t") and "newOutput", (matched by "Eval_IO(newInt,newOutput)" with the evaluation of "(doSomething monad)" - "eval_IO u").<br />
<br />
That is to say: in the "where" clause, we are matching for the<br />
elements paired in a type Eval_IO: this is indeed the type of "monad"<br />
(corresponding to "eval_IO t" in the body of the evaluator) and<br />
"(doSomething monad)" (where "doSomething" correspond to the<br />
evaluation of "eval_IO u" within an anonymous function with \oldInt as<br />
its argument, argument bound to the result of the previous evaluation<br />
of "monad", that is to say "eval_IO t").<br />
<br />
And so, "Eval_IO (oldInt,oldOutput) = monad" means: match "oldInt" and<br />
"oldOutput", paired in a type Eval_IO, and that are produced by the<br />
evaluation of "monad" (that is to say: "eval_IO t"). The same for<br />
Eval_IO (newInt,newOutput): match "newInt" and "newOutput" produced by<br />
the evaluation of "(doSomething monad)".<br />
<br />
So the output of the evaluator is now not simply a pair made of and<br />
Int and a String. It is a specific type (Eval_IO) that happens to<br />
carry a pair of an Int and a String. But, if we want the Int and the<br />
string, we have to extract them from the Eval_IO type, as we do in the<br />
"where" clause: we ''unpack'' our type object (let's call it with its<br />
name: our monad!) and take out the Int and the String to feed the next<br />
function application and the output generation.<br />
<br />
The same to insert something in our monad: if we want to create a pair<br />
of an Int and a String, pair of type Eval_IO, we now have to ''pack''<br />
them together by using our type constructor, feeding it with a pair<br />
composed by and Int and a String. This is what we do with the "return"<br />
method of out monad and with "print_IO" function, where:<br />
* return insert into the monad an Int;<br />
* print_IO insert into the monad a String.<br />
<br />
So, why cannot we use the old <hask>type MO a = (a, Out)</hask> that<br />
did not required all this additional work (apart the need to<br />
specifically define (>>)?<br />
<br />
Type MO is just a synonymous for (a,Out): the two can be substituted<br />
one for the other. That's it.<br />
<br />
We did not have to pack "a" and "Out" together with a type constructor<br />
to have a new type MO.<br />
<br />
As a consequence, we cannot use MO as an instance of Monad, and so, we<br />
cannot use with it the syntactic sugar we needed: the do-notation.<br />
<br />
That is to say: a type created with the "type" keyword cannot be an<br />
instance of a class, and cannot inherits its methods (in our case<br />
(>>=, >> and return). And without those methods the do-notation is not<br />
usable.<br />
<br />
==Errare monadicum est==<br />
<br />
Now that we have a basic understanding of what a monad is, and does,<br />
we will further explore it by making some changes to our evaluator.<br />
<br />
In this section we will se how to handle exceptions in our monadic<br />
evaluator.<br />
<br />
Suppose that we want to stop the execution of our monad if some<br />
conditions occurs. If our evaluator was to compute divisions, instead<br />
of sums, then we would like to stop the evaluator when a division by<br />
zero occurs, possibly producing some output, instead of the result of<br />
the evaluation of the expression, that explains what happened.<br />
<br />
Basic error handling.<br />
<br />
We will do so starting from the beginning once again...<br />
<br />
===The basic evaluator, non monadic, with exception===<br />
<br />
We just take our basic evaluator, without any output, and write a<br />
method to stop execution if a condition occurs: <br />
<br />
<haskell><br />
<br />
> data M a = Raise Exception<br />
> | Return a<br />
> deriving (Show)<br />
> type Exception = String<br />
<br />
</haskell><br />
<br />
Now, our monad is of datatype "M a" which can either be constructed<br />
with the "Raise" constructor, that takes a String (Exception is a<br />
synonymous of String), or by the "Return" constructor, that takes a<br />
variable type ("a"), an Int in our case.<br />
<br />
<haskell><br />
<br />
> evalE :: Term -> M Int<br />
> evalE (Con a) = Return a<br />
<br />
</haskell><br />
<br />
If evalE matches a Con it will construct a type Return with, inside, the content of the Con.<br />
<br />
<haskell><br />
<br />
> evalE (Add a b) = <br />
> case evalE a of<br />
> Raise e -> Raise e<br />
> Return a -><br />
> case evalE b of <br />
> Raise e -> Raise e<br />
> Return b -><br />
> if (a+b) == 42<br />
> then Raise "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else Return (a+b)<br />
<br />
</haskell><br />
<br />
If evalE matches an Add it will check if evaluating the first part<br />
produces a "Raise" or a "Return": in the first case it will return a<br />
"Raise" whose content is the same received. <br />
<br />
If instead the evaluation produces a value of a type matched by<br />
"Return", the evaluator will evaluate the second term of Add.<br />
<br />
If this returns a "Raise", a "Raise" will be returned all the way up<br />
the recursion, otherwise the evaluator will check whether a condition<br />
for raising a "Raise" exists. If not, it will return a "Return" with<br />
the sum inside.<br />
<br />
Test it with:<br />
<br />
evalE (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2)))<br />
<br />
<br />
===The basic evaluator, monadic, with exceptions===<br />
<br />
In order to produce a monadic version of the previous evaluator, the<br />
one that raises exceptions, we just need to abstract out from the<br />
evaluator all that case analysis.<br />
<br />
<haskell><br />
<br />
> data M1 a = Except Exception<br />
> | Ok {showM :: a }<br />
> deriving (Show)<br />
<br />
</haskell><br />
<br />
The data type didn't change at all. Well, we changed the name of the<br />
Return type constructor (now Ok) so that this constructor can coexist<br />
with the previous one in the same Literate Haskell file.<br />
<br />
<div id="MonadicEvalE"><br />
<haskell><br />
<br />
> instance Monad M1 where<br />
> return a = Ok a<br />
> m >>= f = case m of<br />
> Except e -> Except e<br />
> Ok a -> f a<br />
<br />
</haskell><br />
<br />
Binding operations are now very easy. Basically we check:<br />
* if the result of the evaluation of "m" produces an exception (first match: Except e ->...), in which case we return its content by constructing our M1 Int with the "Raise" constructor".<br />
* if the result of the evaluation of "m" is matched with the "Ok" constructor, we get its content and use it to bind the argument of "f" to its value.<br />
<br />
<hask>return a</hask> will just use the Ok type constructor for<br />
inserting "a" (in our case an Int) into M1 Int, the type of our monad.<br />
<br />
<haskell><br />
<br />
> raise :: Exception -> M1 a<br />
> raise e = Except e<br />
<br />
</haskell><br />
<br />
This is just a helper function to construct our "M1 a" type with the<br />
Raise constructor. It takes a string and returns a type (M1 a) to be<br />
matched with the "Raise" constructor.<br />
<br />
<haskell><br />
<br />
> eval_ME :: Term -> M1 Int<br />
> eval_ME (Con a) = do return a<br />
> eval_ME (Add t u) = do a <- eval_ME t<br />
> b <- eval_ME u<br />
> if (a+b) == 42<br />
> then raise "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
</haskell><br />
<br />
The evaluator itself is very simple. We bind "a" with the result of<br />
"eval_ME t", "b" with the result of "eval_ME u", and we check for a<br />
condition: <br />
* if the condition is met we raise an exception, that is to say: we return a value constructed with the "Raise" constructor. This value will be matched by ">>=" in the next recursion. And >>= will just return it all the way up the recursion.<br />
* if the condition is not met, we return a value constructed with the "Return" type constructor and go on with the recursion.<br />
<br />
Run with:<br />
<br />
eval_ME (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2)))<br />
<br />
It is noteworthy the fact that in our datatype definition we used a<br />
label field with a label selector (we called it showM), even though it<br />
was not used in our code. We will use this methodology later on.<br />
<br />
So, just to refresh your memory:<br />
<br />
<haskell><br />
<br />
> data Person = Person {name :: String,<br />
> age :: Int,<br />
> hobby :: String<br />
> } deriving (Show)<br />
<br />
> andreaRossato = Person "Andrea" 37 "Haskell The Monadic Way"<br />
> personName (Person a b c) = a<br />
<br />
</haskell><br />
<br />
will produce:<br />
*TheMonadicWay> andreaRossato<br />
Person {name = "Andrea", age = 37, hobby = "Haskell The Monadic Way"}<br />
*TheMonadicWay> personName andreaRossato<br />
"Andrea"<br />
*TheMonadicWay> name andreaRossato<br />
"Andrea"<br />
*TheMonadicWay> age andreaRossato<br />
37<br />
*TheMonadicWay> hobby andreaRossato<br />
"Haskell The Monadic Way"<br />
*TheMonadicWay> <br />
<br />
<br />
===Monadic evaluator with output and exceptions===<br />
<br />
We will now try to combine the [[The Monadic Way/Part I#MonadicEvalIO|output-producing monadic evaluator]] <br />
with [[The Monadic Way/Part I#MonadicEvalE| exception producing one]].<br />
<br />
<br />
<haskell><br />
<br />
> data M2 a = Ex Exception<br />
> | Done {unpack :: (a,O) }<br />
> deriving (Show)<br />
<br />
</haskell><br />
<br />
Now we need a [[algebraic datatype]] with two [[constructor]]s: one to produce a value type "M2 a" using "Ex String" and one for value type "M2 a" (Int in<br />
this case) using "Done a".<br />
<br />
'''Note''' that we changed the name of the exception type constructor<br />
from "Raise" to "Ex" just to make the two coexist in the same [[Literate programming|literate Haskell]] file.<br />
<br />
The constructor "Done a" is defined with a label selector: <hask>Done {unpack :: (a,O)}</hask> <br />
and is equivalent to <hask>Done (a,O)</hask>. <br />
<br />
The only difference is that, this way, we are also defining a method<br />
to retrieve the pair (a,O) (in our case "O" is a synonymous for<br />
String, whereas "a" is a variable type) from an object of type "Done<br />
a".<br />
<br />
<haskell><br />
<br />
> instance Monad M2 where<br />
> return a = Done (a, "")<br />
> m >>= f = case m of<br />
> Ex e -> Ex e<br />
> Done (a, x) -> case (f a) of<br />
> Ex e1 -> Ex e1<br />
> Done (b, y) -> Done (b, x ++ y)<br />
<br />
</haskell><br />
<br />
Now our binding operations gets more complicated by the fact that we<br />
have to concatenate the output, as we did before, '''and''' check for<br />
exceptions.<br />
<br />
It is not possible to do has we did in the [[The Monadic Way/Part I#MonadicEvalE| exception producing evaluator]], <br />
where we could check just for "m" (remember the "m" in the first run<br />
stands for "eval t").<br />
<br />
Since at the end we must return the output produced by the evaluation<br />
of "m" ''concatenated'' with the output produced by the evaluation of<br />
"f a" (where "a" is returned by "m", paired with "x" by "Done"), now<br />
we must check if we '''do have''' an output from "f a" produced by<br />
"Done".<br />
<br />
Indeed, now, "f a" can also produce a value constructed by "Ex", and<br />
this value does not contain the pair as the value produced by "Done".<br />
<br />
So, we evaluate "m": <br />
* if we match a value produced by type constructor "Ex" we return a value produced by type constructor "Ex" whose content is the one we extracted in the matching;<br />
* if we match a value produced by "Done" we match the pair it carries "(a,x)" and we analyze what "f a" returns:<br />
** if "f a" returns a value produced by "Ex" we extract the exception and we return it, constructing a value with "Ex"<br />
** if "f a" returns a value produced by "Done" we return "b" and the concatenated "x" and "y". <br />
<br />
And now the evaluator:<br />
<br />
<haskell><br />
<br />
> raise_IOE :: Exception -> M2 a<br />
> raise_IOE e = Ex e<br />
<br />
</haskell><br />
<br />
This is the [[function]] to insert an exception in our monad (M2): We take<br />
a String and produce a value applying the type constructor for exception "Ex" to its value.<br />
<br />
<haskell><br />
<br />
> print_IOE :: O -> M2 ()<br />
> print_IOE x = Done ((), x)<br />
<br />
</haskell><br />
<br />
The function to produce output is the very same of the one of the [[The Monadic Way/Part I#MonadicEvalIO|output-producing monadic evaluator]].<br />
<br />
<haskell><br />
<br />
> eval_IOE :: Term -> M2 Int<br />
> eval_IOE (Con a) = do print_IOE (formatLine (Con a) a)<br />
> return a<br />
> eval_IOE (Add t u) = do a <- eval_IOE t<br />
> b <- eval_IOE u<br />
> let out = formatLine (Add t u) (a + b)<br />
> print_IOE out<br />
> if (a+b) == 42<br />
> then raise_IOE $ out ++ "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
</haskell><br />
<br />
The evaluator procedure did not change very much from the one of the [[The Monadic Way/Part I#MonadicEvalIO|output-producing monadic evaluator]].<br />
<br />
We just added the case analysis to see if the condition for raising an exception is met.<br />
<br />
Running with<br />
<br />
eval_IOE (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2)))<br />
<br />
will produce <br />
<br />
Ex "eval (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2))) <= 42 - <br />
The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
<br />
Look at the <hask>let</hask> clause within the do-notation. We do not<br />
need to use the "let ... in" construction: since all [[bound variable]]s<br />
remain bound within a <hask>do</hask> procedure (see [[The Monadic Way/Part I#Bind|here]]), <br />
we do not need the "in" to specify "where" the variable "out" will be bound in!<br />
<br />
==We need a state==<br />
<br />
We will keep on adding complexity to our monadic evaluator and this<br />
time we will add a counter. We just want to count the number of<br />
iterations (the number of times "eval" will be called) needed to<br />
evaluate the expression.<br />
<br />
===The basic evaluator, non monadic, with a counter===<br />
<br />
As before we will start by adding this feature to our [[The Monadic Way Part I#BasicEval|basic evaluator]]. <br />
<br />
A method to count the number of iterations, since the lack of<br />
assignment and destructive updates (such as for i=0;i<10;i++;),<br />
is to add an argument to our function, the initial state, number that<br />
in each call of the function will be increased and passed to the next<br />
function call.<br />
<br />
And so, very simply:<br />
<br />
<haskell><br />
<br />
> -- non monadic<br />
> type St a = State -> (a, State)<br />
> type State = Int<br />
> evalNMS :: Term -> St Int<br />
> evalNMS (Con a) x = (a, x + 1)<br />
> evalNMS (Add t u) x = let (a, y) = evalNMS t x in<br />
> let (b, z) = evalNMS u y in<br />
> (a + b, z +1)<br />
<br />
</haskell><br />
<br />
Now evalNMS takes two arguments: the expression of type Term and an<br />
State (which is a synonymous for Int), and will produce a pair<br />
(a,State), that is to say a pair with a variable type "a" and an Int.<br />
<br />
The operations in the evaluator are very similar to the non monadic [[The Monadic Way Part I#BasivEvalO|output producing evaluator]].<br />
<br />
We are now using the "let ... in" clause, instead of the "where", and we are increasing the counter "z" the comes from the evaluation of the second term, but the basic operation are the same:<br />
* we evaluate "evalNMS t x" where "x" is the initial state, and we match and bind the result in "let (a, y) ... in"<br />
* we evaluate "evalNMS u y", where "y" was bound to the value returned by the previous evaluation, and we match and bind the result in "let (b, z) ... in"<br />
* we return a pair formed by the sum of the result (a+b) and the state z increased by 1. <br />
<br />
Let's try it:<br />
<br />
*TheMonadicWay> evalNMS (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2))) 0<br />
(42,7)<br />
*TheMonadicWay> <br />
<br />
As you see we must pass to "evalNMS"the initial state of our counter: 0.<br />
<br />
Look at the type signature of the function "evalNMS":<br />
<haskell><br />
evalNMS :: Term -> St Int<br />
</haskell><br />
<br />
From this signature you could argue that our function takes only<br />
'''one''' argument. But since our type St is defined with the "type"<br />
keyword, St can be substituted with what comes after the "=" sign. So,<br />
the real type signature of our function is:<br />
<br />
<haskell><br />
evalNMS :: Term -> State -> (Int,State)<br />
</haskell><br />
<br />
<div if="typeNewtype"><br />
Just to refresh your memory:<br />
<br />
<haskell><br />
<br />
> type IamAfunction a = (a -> a)<br />
> newtype IamNotAfunction a = NF (a -> a)<br />
> newtype IamNotAfunctionButYouCanUnPackAndRunMe a = F { unpackAndRun :: (a -> a) }<br />
<br />
> a = \x -> x * x<br />
<br />
> a1 :: IamAfunction Integer<br />
> a1 = a<br />
<br />
> a2 :: IamNotAfunction Integer<br />
> a2 = NF a<br />
<br />
> a3 :: IamNotAfunctionButYouCanUnPackAndRunMe Integer<br />
> a3 = F a<br />
<br />
</haskell><br />
<br />
<br />
*TheMonadicWay> a 4<br />
16<br />
*TheMonadicWay> a1 4<br />
16<br />
*TheMonadicWay> a2 4<br />
<br />
<interactive>:1:0:<br />
The function `a2' is applied to one arguments,<br />
but its type `IamNotAfunction Int' has only 0<br />
In the definition of `it': it = a2 4<br />
*TheMonadicWay> a3 4<br />
<br />
<interactive>:1:0:<br />
The function `a3' is applied to one arguments,<br />
but its type `IamNotAfunctionButYouCanUnPackAndRunMe Int' has only 0<br />
In the definition of `it': it = a3 4<br />
*TheMonadicWay> unpackAndRun a3 4<br />
16<br />
*TheMonadicWay><br />
<br />
This means that "a1" is a partial application hidden by a type<br />
synonymous. <br />
<br />
"a2" and "a3" are not function types. They are types that<br />
have a functional value. <br />
<br />
Moreover, since we defined the type constructor of type<br />
"IamNotAfunctionButYouCanUnPackAndRunMe", F, with a label field, in<br />
that label field we defined a method (a label selector) to "extract"<br />
the function from the type "IamNotAfunctionButYouCanUnPackAndRunMe",<br />
and run it:<br />
<br />
<haskell><br />
unpackAndRun a3 4<br />
</haskell><br />
<br />
And what about "a2"? Is it lost forever?<br />
<br />
Obviously not! We need to write a function that unpacks a type<br />
"IamNotAfunction", using its type constructor NF to match the internal<br />
function:<br />
<br />
<haskell><br />
<br />
> unpackNF :: IamNotAfunction a -> a -> a<br />
> unpackNF (NF f) = f<br />
<br />
</haskell><br />
<br />
and run:<br />
<br />
*TheMonadicWay> unpackNF a2 4<br />
16<br />
*TheMonadicWay> <br />
<br />
As you see, "unpackNF" definition is a partial application: we specify<br />
one argument to get a function that gets another argument.<br />
<br />
A label selector does the same thing.<br />
<br />
Later we will see the importance of this distinction, quite obvious<br />
for haskell gurus, but not for us. Till now.<br />
<br />
===The evaluator, monadic, with a counter===<br />
<br />
We will now rewrite our basic evaluator with the counter in<br />
do-notation.<br />
<br />
As we have seen, in order to do so we need:<br />
* a new type that we must declare as an instance of the Monad class;<br />
* a function for binding method (>>=) and a function for the "return" method, for the instance declaration; <br />
<br />
Now our type will be holding a function that will take the initial<br />
state 0 as we did before.<br />
<br />
In order to simplify the process of unpacking the monad each time to<br />
get the function, we will use a label sector:<br />
<br />
<haskell><br />
<br />
> newtype MS a = MS { unpackMSandRun :: (State -> (a, State)) }<br />
<br />
</haskell><br />
<br />
This is it: MS will be our type constructor for matching and for<br />
building our monad. "unpackMSandRun" will be the method to get the<br />
function out of the monad to feed it with the initial state of the<br />
counter, 0, to get our result.<br />
<br />
Then we need the "return" function that, as we have seen does nothing<br />
but inserting into our monad an Integer:<br />
<br />
<haskell><br />
<br />
> mkMS :: a -> MS a<br />
> mkMS int = MS (\x -> (int, x))<br />
<br />
</haskell><br />
<br />
"mkMS" will just take an Integer "a" and apply the MS type constructor<br />
to our anonymous function that takes an initial state and produces the<br />
final state "x" and the integer "a".<br />
<br />
In other words, we are just creating our monad with inside an Integer.<br />
<br />
Our binding function will be a bit more complicated then before. We<br />
must create a type that holds an anonymous function with elements to<br />
be extracted from our type and passed to the anonymous function that<br />
comes next:<br />
<br />
<haskell><br />
<br />
> bindMS :: MS a -> (a -> MS b) -> MS b<br />
> bindMS monad doNext = MS $ \initialState -> <br />
> let (oldInt, oldState) = unpackMSandRun monad initialState in<br />
> let (newInt, newState) = unpackMSandRun (doNext oldInt) oldState in<br />
> (newInt,newState)<br />
<br />
</haskell><br />
<br />
So, we are creating an anonymous function that will take an initial<br />
state, 0, and return a "newInt" and "newState". <br />
<br />
To do that we need to unpack and run our "monad" against the<br />
initialState in order to get the "oldInt" and the "oldState".<br />
<br />
The "oldInt" will be passed to the "doNext" function (the next<br />
anonymous function in our do block) together with the "oldState" to<br />
get the "newInt" and the "newState".<br />
<br />
We can now declare our type "MS" as an instance of the Monad class:<br />
<haskell><br />
<br />
> instance Monad MS where<br />
> return a = mkMS a<br />
> (>>=) m f = bindMS m f<br />
<br />
</haskell><br />
<br />
We now need a function to increase the counter in our monad from<br />
within a do block:<br />
<br />
<haskell><br />
<br />
> incState :: MS ()<br />
> incState = MS (\s -> ((), s + 1))<br />
<br />
</haskell><br />
<br />
This is easier then it looks like. We use the type constructor MS to<br />
create a function that takes a state an returns a void integer ()<br />
paired with the state increased by one. We do not need any binding,<br />
since we are just modifying the state, an integer, and, in our do<br />
block, we will insert this function before a new line, so that the non<br />
binding ">>" operator will be applied.<br />
<br />
And now the evaluator:<br />
<br />
<haskell><br />
<br />
> evalMS :: Term -> MS Int<br />
> evalMS (Con a) = do incState<br />
> mkMS a<br />
> evalMS (Add t u) = do a <- evalMS t<br />
> b <- evalMS u<br />
> incState <br />
> return (a + b)<br />
<br />
</haskell><br />
<br />
Very easy: we just added the "incState" function before returning the<br />
sum of the evaluation of the Terms of our expression.<br />
<br />
Let's try it:<br />
<br />
*TheMonadicWay> unpackMSandRun (evalMS (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12))))) 0<br />
(54,7)<br />
*TheMonadicWay> <br />
<br />
As you can see, adding a counter makes our binding operations a bit<br />
more complicated by the fact that we have an anonymous function within<br />
our monad. This means that we must recreate that anonymous function in<br />
each step of our do block. This makes "incState" and, as we are going<br />
to see in the next paragraph, the function to produce output a bit<br />
more complicated. Anyway we can handle this complexity quite well, for<br />
now.<br />
<br />
===The monadic evaluator with output and counter in do-notation===<br />
<br />
Adding output to our evaluator is now quite easy. It's just a matter<br />
of adding a field to our type, where we are going to accumulate the<br />
output, and take care of extracting it in our bind function to<br />
concatenate the old one with the new one.<br />
<br />
<haskell><br />
<br />
> newtype Eval_SIO a = Eval_SIO { unPackMSIOandRun :: State -> (a, State, Output) }<br />
<br />
</haskell><br />
<br />
Now our monad contains an anonymous function that takes the initial<br />
state, 0, and will produce the final Integer, the final state and the<br />
concatenated output.<br />
<br />
So, this is bind:<br />
<br />
<haskell><br />
<br />
> bindMSIO monad doNext = <br />
> Eval_SIO (\initialState -><br />
> let (oldInt, oldState, oldOutput) = unPackMSIOandRun monad initialState in<br />
> let (newInt, newState, newOutput) = unPackMSIOandRun (doNext oldInt) oldState in<br />
> (newInt, newState, oldOutput ++ newOutput))<br />
<br />
</haskell><br />
<br />
And this is our "return":<br />
<haskell><br />
<br />
> mkMSIO int = Eval_SIO (\s -> (int, s, ""))<br />
<br />
</haskell><br />
<br />
Now we can declare our type, "Eval_SIO", as an instance of the Monad class:<br />
<br />
<haskell><br />
<br />
> instance Monad Eval_SIO where<br />
> return a = mkMSIO a<br />
> (>>=) m f = bindMSIO m f<br />
<br />
</haskell><br />
<br />
Now, the function to increment the counter will also insert an empty<br />
string "" in our monad: "bind" will take care of concatenating it with<br />
the old output:<br />
<br />
<haskell><br />
<br />
> incSIOstate :: Eval_SIO () <br />
> incSIOstate = Eval_SIO (\s -> ((), s + 1, ""))<br />
<br />
</haskell><br />
<br />
The function to insert some new output will just insert a string into<br />
our monad, together with a void Integer (). Since no binding will<br />
occur (>> will be applied), the () will not be taken into<br />
consideration within the anonymous functions automatically created for<br />
us within the do block:<br />
<br />
<haskell><br />
<br />
> print_SIO :: Output -> Eval_SIO ()<br />
> print_SIO x = Eval_SIO (\s -> ((),s, x))<br />
<br />
</haskell><br />
<br />
And now the evaluator, that puts everything together. As you can see<br />
it did not change too much from the previous versions:<br />
<br />
<haskell><br />
<br />
> eval_SIO :: Term -> Eval_SIO Int<br />
> eval_SIO (Con a) = do incSIOstate<br />
> print_SIO (formatLine (Con a) a)<br />
> return a<br />
> eval_SIO (Add t u) = do a <- eval_SIO t<br />
> b <- eval_SIO u<br />
> incSIOstate<br />
> print_SIO (formatLine (Add t u) (a + b))<br />
> return (a + b)<br />
<br />
</haskell><br />
<br />
Running it will require unpacking the monad and feeding it with the initial state 0:<br />
<br />
unPackMSIOandRun (eval_SIO (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12))))) 0<br />
*TheMonadicWay> unPackMSIOandRun (eval_SIO (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12))))) 0<br />
(54,7,"eval (Con 6) <= 6 - eval (Con 16) <= 16 - <br />
eval (Con 20) <= 20 - <br />
eval (Con 12) <= 12 - <br />
eval (Add (Con 20) (Con 12)) <= 32 - <br />
eval (Add (Con 16) (Add (Con 20) (Con 12))) <= 48 - <br />
eval (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <= 54 - ")<br />
*TheMonadicWay> <br />
<br />
(I formatted the output).<br />
<br />
<br />
==If there's a state we need some discipline: Dealing with complexity==<br />
<br />
'''(Text to be done yet: just a summary)'''<br />
<br />
In order to increase the complexity of our monad now we will try to<br />
mix State (counter), Exceptions and Output.<br />
<br />
This is an email [http://www.haskell.org/pipermail/haskell-cafe/2006-August/017672.html I send to the haskell-cafe mailing list]:<br />
<br />
<pre><br />
Now I'm trying to create a statefull evaluator, with output and<br />
exception, but I'm facing a problem I seem not to be able to<br />
conceptually solve.<br />
<br />
Take the code below.<br />
Now, in order to get it run (and try to debug) the Eval_SOI type has a<br />
Raise constructor that produces the same type of SOIE. Suppose instead it<br />
should be constructing something like Raise "something". <br />
Moreover, I wrote a second version of >>=, commented out.<br />
This is just to help me illustrate to problem I'm facing.<br />
<br />
Now, >>= is suppose to return Raise if "m" is matched against Raise<br />
(second version commented out).<br />
If "m" matches SOIE it must return a SOIE only if "f a" does not<br />
returns a Raise (output must be concatenated).<br />
<br />
I seem not to be able to find a way out. Moreover, I cannot understand<br />
if a way out can be possibly found. Something suggests me it could be<br />
related to that Raise "something".<br />
But my feeling is that functional programming could be something out<br />
of the reach of my mind... by the way, I teach Law, so perhaps you'll<br />
forgive me...;-)<br />
<br />
If you can help me to understand this problem all I can promise is<br />
that I'll mention your help in the tutorial I'm trying to write on<br />
"the monadic way"... that seems to lead me nowhere.<br />
<br />
Thanks for your kind attention.<br />
<br />
Andrea<br />
</pre><br />
<br />
This was the code:<br />
<br />
<haskell><br />
data Eval_SOI a = Raise { unPackMSOIandRun :: State -> (a, State, Output) }<br />
| SOIE { unPackMSOIandRun :: State -> (a, State, Output) }<br />
<br />
instance Monad Eval_SOI where<br />
return a = SOIE (\s -> (a, s, ""))<br />
m >>= f = SOIE (\x -><br />
let (a, y, s1) = unPackMSOIandRun m x in<br />
case f a of<br />
SOIE nextRun -> let (b, z, s2) = nextRun y in <br />
(b, z, s1 ++ s2)<br />
Raise e1 -> e1 y --only this happens<br />
<br />
)<br />
-- (>>=) m f = case m of<br />
-- Raise e -> error "ciao" -- why this is not going to happen?<br />
-- SOIE a -> SOIE (\x -><br />
-- let (a, y, s1) = unPackMSOIandRun m x in<br />
-- let (b, z, s2) = unPackMSOIandRun (f a) y in <br />
-- (b, z, s1 ++ s2)) <br />
<br />
<br />
incSOIstate :: Eval_SOI ()<br />
incSOIstate = SOIE (\s -> ((), s + 1, ""))<br />
<br />
print_SOI :: Output -> Eval_SOI ()<br />
print_SOI x = SOIE (\s -> ((),s, x))<br />
<br />
raise x e = Raise (\s -> (x,s,e))<br />
<br />
eval_SOI :: Term -> Eval_SOI Int<br />
eval_SOI (Con a) = do incSOIstate<br />
print_SOI (formatLine (Con a) a)<br />
return a<br />
eval_SOI (Add t u) = do a <- eval_SOI t<br />
b <- eval_SOI u<br />
incSOIstate<br />
print_SOI (formatLine (Add t u) (a + b))<br />
if (a + b) == 42 <br />
then raise (a+b) " = The Ultimate Answer!!"<br />
else return (a + b)<br />
<br />
runEval exp = case eval_SOI exp of<br />
Raise a -> a 0<br />
SOIE p -> let (result, state, output) = p 0 in<br />
(result,state,output)<br />
<br />
<br />
<br />
--runEval (Add (Con 10) (Add (Con 28) (Add (Con 40) (Con 2))))<br />
</haskell><br />
<br />
This code will produce <br />
<br />
eval (Con 10) <= 10 -<br />
eval (Con 28) <= 28 -<br />
eval (Con 40) <= 40 -<br />
eval (Con 2) <= 2 - = The Ultimate Answer!!<br />
eval (Add (Con 28) (Add (Con 40) (Con 2))) <= 70 -<br />
eval (Add (Con 10) (Add (Con 28) (Add (Con 40) (Con 2)))) <= 80 -<br />
<br />
The exception appears in the output, but executioon is not stopped.<br />
<br />
===Monadic evaluator with output, counter and exception, in do-notation===<br />
<br />
Brian Hulley [http://www.haskell.org/pipermail/haskell-cafe/2006-August/017680.html came up with this solution]:<br />
<br />
<haskell><br />
<br />
> -- thanks to Brian Hulley<br />
> data Result a<br />
> = Good a State Output<br />
> | Bad State Output Exception<br />
> deriving Show<br />
<br />
> newtype Eval_SIOE a = SIOE {runSIOE :: State -> Result a}<br />
<br />
> instance Monad Eval_SIOE where<br />
> return a = SIOE (\s -> Good a s "")<br />
> m >>= f = SIOE $ \x -><br />
> case runSIOE m x of<br />
> Good a y o1 -><br />
> case runSIOE (f a) y of<br />
> Good b z o2 -> Good b z (o1 ++ o2)<br />
> Bad z o2 e -> Bad z (o1 ++ o2) e<br />
> Bad z o2 e -> Bad z o2 e<br />
<br />
> raise_SIOE e = SIOE (\s -> Bad s "" e)<br />
<br />
> incSIOEstate :: Eval_SIOE ()<br />
> incSIOEstate = SIOE (\s -> Good () (s + 1) "")<br />
<br />
> print_SIOE :: Output -> Eval_SIOE ()<br />
> print_SIOE x = SIOE (\s -> Good () s x)<br />
<br />
<br />
> eval_SIOE :: Term -> Eval_SIOE Int<br />
> eval_SIOE (Con a) = do incSIOEstate<br />
> print_SIOE (formatLine (Con a) a)<br />
> return a<br />
> eval_SIOE (Add t u) = do a <- eval_SIOE t<br />
> b <- eval_SIOE u<br />
> incSIOEstate<br />
> let out = formatLine (Add t u) (a + b)<br />
> print_SIOE out<br />
> if (a+b) == 42<br />
> then raise_SIOE $ out ++ "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
> runEval exp = case runSIOE (eval_SIOE exp) 0 of<br />
> Bad s o e -> "Error at iteration n. " ++ show s ++ <br />
> " - Output stack = " ++ o ++ <br />
> " - Exception = " ++ e<br />
> Good a s o -> "Result = " ++ show a ++ <br />
> " - Iterations = " ++ show s ++ " - Output = " ++ o<br />
<br />
</haskell><br />
<br />
Run with runEval (Add (Con 18) (Add (Con 12) (Add (Con 10) (Con 2))))<br />
<br />
==Suggested readings==<br />
<br />
:Cale Gibbard, [[Monads as containers]]<br />
:Jeff Newbern, [http://haskell.org/all_about_monads/html/contmonad.html All About Monads]<br />
:[[IO inside]]<br />
:[http://sigfpe.blogspot.com/2006/08/you-could-have-invented-monads-and.html You Could Have Invented Monads! (And Maybe You Already Have.) by sigfpe]<br />
<br />
<br />
==Acknowledgments==<br />
<br />
Thanks to Neil Mitchell, Daniel Fisher, Bulat Ziganzhin, Brian Hulley<br />
and Udo Stenzel for the invaluable help they gave, in the<br />
[http://www.haskell.org/mailman/listinfo/haskell-cafe haskell-cafe mailing list], <br />
in understanding this topic.<br />
<br />
I couldn't do it without their help.<br />
<br />
Obviously errors are totally mine. But this is a wiki so, please,<br />
correct them!<br />
<br />
- [[User:AndreaRossato|Andrea Rossato]]<br />
<br />
[[Category:Tutorials]]<br />
[[Category:Monad]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=The_Monadic_Way/Part_I&diff=14662The Monadic Way/Part I2007-07-24T22:41:41Z<p>BrettGiles: /* Monadic evaluator with output and exceptions */ links</p>
<hr />
<div>'''Note: this is the first part of [[The Monadic Way]]'''<br />
==An evaluation of Philip Wadler's "Monads for functional programming"==<br />
<br />
This tutorial is a "translation" of Philip Wadler's [http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf "Monads for functional programming"].<br />
(avail. from [http://homepages.inf.ed.ac.uk/wadler/topics/monads.html here])<br />
<br />
I'm a Haskell newbie trying to grasp such a difficult concept as the<br />
one of Monad and monadic computation.<br />
<br />
While [http://www.cs.utah.edu/~hal/htut/ "Yet Another Haskell Tutorial"] <br />
gave me a good understanding of the type system when it<br />
comes to monads I find it almost unreadable.<br />
<br />
But I had also Wadler's paper, and started reading it. Well, just<br />
wonderful! It explains how to ''create'' a monad!<br />
<br />
So I decided to "translate it", in order to clarify to myself the<br />
topic. And I'm now sharing this traslation ('''not completed yet'')<br />
with the hope it will be useful to someone else.<br />
<br />
Moreover, that's a wiki, so please improve it. And, specifically,<br />
correct my poor English. I'm Italian, after all.<br />
<br />
'''Note: The source of this page can be used as a Literate Haskell<br />
file and can be run with ghci or hugs: so cut paste change and run (in<br />
emacs for instance) while reading it...'''<br />
<br />
==A simple evaluator==<br />
<br />
Let's start with something simple: suppose we want to implement a new<br />
programming language. We just finished with<br />
[http://swiss.csail.mit.edu/classes/6.001/abelson-sussman-lectures/ Abelson and Sussman's Structure and Interpretation of Computer Programs] <br />
and we want to test what we have learned.<br />
<br />
Our programming language will be very simple: it will just compute the<br />
sum of two terms.<br />
<br />
So we have just one primitive operation (Add) that takes two constants<br />
and calculates their sum.<br />
<br />
Moreover we have just one kind of data type: Con a, which is an Int.<br />
<br />
For instance, something like:<br />
<br />
(Add (Con 5) (Con 6))<br />
<br />
should yield:<br />
<br />
11<br />
<br />
===The basic evaluator===<br />
<br />
We will implement our language with the help of a data type<br />
constructor such as:<br />
<br />
<div id="BasicEval"><br />
<haskell><br />
<br />
> module TheMonadicWay where<br />
> data Term = Con Int<br />
> | Add Term Term<br />
> deriving (Show)<br />
<br />
</haskell><br />
<br />
After that we build our interpreter:<br />
<br />
<haskell><br />
<br />
> eval :: Term -> Int<br />
> eval (Con a) = a<br />
> eval (Add a b) = eval a + eval b<br />
<br />
</haskell><br />
<br />
That's it. Just an example:<br />
<br />
*TheMonadicWay> eval (Add (Con 5) (Con 6))<br />
11<br />
*TheMonadicWay><br />
<br />
Very very simple. The evaluator checks if its argument is of type Con<br />
Int: if it is it just returns the Int.<br />
<br />
If the argument is not of type Con, but it is of type Term, it<br />
evaluates the first Term and sums the result with the result of the<br />
evaluation of the second Term.<br />
<br />
As you may understand, our evaluator uses some of the powerful<br />
features of Haskell type system. Instead of writing a parser that<br />
takes a string (the user input) and transforms that string into an<br />
expression to be evaluated, we use the two type constructors defined<br />
for our data type Term (Con and Add) to build the expression - such as<br />
(Add (Con 5) (Con 6)) - and to match the expression's elements in our<br />
"eval" function.<br />
<br />
<br />
== Some output, please!==<br />
<br />
Now, that's fine, but we'd like to add some features, like providing<br />
some output, to show how the computation was carried out.<br />
<br />
Well, but Haskell is a pure functional language, with no side effects,<br />
we were told.<br />
<br />
Now we seem to be wanting to create a side effect of the computation,<br />
its output, and be able to stare at it...<br />
<br />
If we had some global variable to store the out that would be<br />
simple...<br />
<br />
But we can create the output and carry it along the computation,<br />
concatenating it with the old one, and present it at the end of the<br />
evaluation together with the evaluation of the expression given to our<br />
evaluator/interpreter!<br />
<br />
===The basic evaluator with output===<br />
<br />
Simple and neat:<br />
<div id="BasivEvalO"><br />
<haskell><br />
<br />
> type MOut a = (a, Output)<br />
> type Output = String<br />
> <br />
> formatLine :: Term -> Int -> Output<br />
> formatLine t a = "eval (" ++ show t ++ ") <= " ++ show a ++ " - " <br />
> <br />
> evalO :: Term -> MOut Int<br />
> evalO (Con a) = (a, formatLine (Con a) a)<br />
> evalO (Add t u) = ((a + b),(x ++ y ++ formatLine (Add t u) (a + b)))<br />
> where (a, x) = evalO t<br />
> (b, y) = evalO u<br />
<br />
</haskell><br />
<br />
Now we have what we want. But we had to change our evaluator quite a<br />
bit. <br />
<br />
First we added a function, formatLine, that takes an argument of type<br />
Term (the expression to be evaluated), one of type Int (the result of<br />
the evaluation of Term) and gives back an output of type Output (that<br />
is a synonymous of String). This is just a helper function to format<br />
the string to output. Not very interesting at all.<br />
<br />
The evaluator itself changed quite a lot! Now it has a different type<br />
signature: it takes an argument of type Term and produces a new type,<br />
we called it MOut, that is actually a compound pair of a variable type<br />
a (an Int in our evaluator) and a type Output, a string.<br />
<br />
So our evaluator, now, will take a Term (the type of the expressions<br />
in our new programming language) and will produce a pair, composed of<br />
the result of the evaluation (an Int) and the Output, a string.<br />
<br />
So far so good. But what's happening inside the evaluator?<br />
<br />
The first part will just return a pair with the number evaluated ("a")<br />
and the output formatted by formatLine.<br />
<br />
The second part does something more complicated: it returns a pair<br />
composed by <br />
1. the result of the evaluation of the right Term summed to the result<br />
of the evaluation of the second Term<br />
2. the output: the concatenation of the output produced by the<br />
evaluation of the right Term, the output produced by the evaluation of<br />
the left Term (each this evaluation returns a pair with the number and<br />
the output), and the formatted output of the evaluation.<br />
<br />
Let's try it:<br />
*TheMonadicWay> evalO (Add (Con 5) (Con 6))<br />
(11,"eval (Con 5) <= 5 - eval (Con 6) <= 6 - eval (Add (Con 5) (Con 6)) <= 11 - ")<br />
*TheMonadicWay><br />
<br />
It works! Let's put the output this way:<br />
eval (Con 5) <= 5 - <br />
eval (Con 6) <= 6 - <br />
eval (Add (Con 5) (Con 6)) <= 11 -<br />
<br />
Great! We are able to produce a side effect of our evaluation and<br />
present it at the end of the computation, after all.<br />
<br />
Let's have a closer look at this expression:<br />
<haskell><br />
<br />
evalO (Add t u) = ((a + b),(x ++ y ++ formatLine (Add t u) (a + b)))<br />
where (a, x) = evalO t<br />
(b, y) = evalO u<br />
<br />
</haskell><br />
<br />
Why all that? The problem is that we need:<br />
* "a" and "b" to calculate their sum (a + b), that will be the first element of the compund pair rapresenting the type (MOut) our evaluator will return <br />
* "x and "y" (the output of each evaluation) to be concatenated with the ourput of formatLine by the expression (x ++ y ++ formatLine(...)): this will be the second element of the compound pair MOut, the string part.<br />
<br />
So we need to separate the pairs produced by "evalO t" and "evalO u".<br />
<br />
We do that within the where clause (remember: evalO now produces a value of type<br />
MOut Int, i.e. a pair of an Int and a String).<br />
<br />
Then we use the single element, "extraded" within the where clause, to<br />
return a new MOut composed by <br />
<br />
((a + b),(x ++ y ++ formatLine (Add t u) (a + b))).<br />
------ -------------------------------------<br />
Int Output = String<br />
<br />
== Let's go monadic==<br />
<br />
Is there a more general way of doing so?<br />
<br />
Let's analyze the evaluator from another perspective. From the type<br />
perspective.<br />
<br />
We solved our problem by creating a new type, a pair of an Int (the<br />
result of the evaluation) and a String (the output of the process of<br />
evaluation).<br />
<br />
The first part of the evaluator does nothing else but creating, from a<br />
value of type Int, an object of type MOut Int (Int,Output). It does so<br />
by creating a pair with that Int and some text produced by formatLine.<br />
<br />
The second part evaluates the two Term(s) and "stores" the values thus<br />
produced in some variables to be use later to compute the output.<br />
<br />
Let's focus on the "stores" action. The correct term should be<br />
"binds".<br />
<br />
Take a function:<br />
<haskell><br />
f x = x + x<br />
</haskell><br />
"x" appears on both sides of the expression. We say that on the right<br />
side "x" is bound to the value of x given on the left side.<br />
<br />
So<br />
<haskell><br />
f 3<br />
</haskell><br />
binds x to 3 for the evaluation of the expression "x + x".<br />
<br />
Our evaluator binds "a" and "x" / "b" and "y" with the evaluation of<br />
"evalO t" and "evalO u" respectively. <br />
<br />
Then "a","b","x" and "y" will be used in the evaluation of<br />
((a+b),(x++y++formatLine)), that will produce a value of type MOut Int:<br />
<br />
<pre><br />
<br />
((a + b),(x ++ y ++ formatLine (Add t u) (a + b))).<br />
------ -------------------------------------<br />
\ / \ /<br />
Int Output = String<br />
---------------------------------<br />
\ /<br />
MOut Int <br />
</pre><br />
<br />
The binding happens in the "where" clause:<br />
<haskell><br />
where (a, x) = evalO t<br />
(b, y) = evalO u<br />
</haskell><br />
<br />
We know that there is an ad hoc operator for binding variables to a<br />
value: lambda, or \.<br />
<br />
Indeed f x = x + x is syntactic sugar for:<br />
<haskell><br />
f = \x -> x + x<br />
</haskell><br />
When we write f 3 we are actually binding "x" to 3 within what's next<br />
"->", that will be used (substituted) for evaluating f 3.<br />
<br />
So we can try to abstract this phenomenon.<br />
<br />
===Monadic evaluator with output===<br />
What we need is a function that takes our composed type MOut Int and a<br />
function in order to produce a new MOut Int, concatenating the<br />
output of the computation of the first with the output of the<br />
computation of the second.<br />
<br />
This is what bindM does:<br />
<br />
<haskell><br />
<br />
> bindM :: MOut a -> (a -> MOut b) -> MOut b<br />
> bindM m f = (b, x ++ y)<br />
> where (a, x) = m<br />
> (b, y) = f a<br />
<br />
</haskell><br />
<br />
It takes:<br />
* "m": the compound type MOut Int carrying the result of an "eval Term",<br />
* a function "f". This function will take the Int ("a") extracted by the evaluation of "m" ((a,x)=m). This function will produce a new pair: a new Int produced by a new evaluation; some new output.<br />
<br />
bindM will return the new Int in pair with the concatenated outputs<br />
resulting from the evaluation of "m" and "f a".<br />
<br />
As you see, we took the binding part out from evalO and put it in this new function.<br />
<br />
So let's write the new version of the evaluator, that we will call evalM_1:<br />
<br />
<haskell><br />
<br />
> evalM_1 :: Term -> MOut Int<br />
> evalM_1 (Con a) = (a, formatLine (Con a) a)<br />
> evalM_1 (Add t u) = bindM (evalM_1 t) (\a -> <br />
> bindM (evalM_1 u) (\b -> <br />
> ((a + b), formatLine (Add t u) (a + b))<br />
> )<br />
> )<br />
<br />
</haskell><br />
<br />
Ugly, isn't it?<br />
<br />
Let's start from the outside:<br />
<br />
<haskell><br />
bindM (evalM_1 u) (\b -> ((a + b), formatLine (Add t u) (a + b)))<br />
</haskell><br />
<br />
bindM takes the result of the evaluation "evalM_1 u", a type Mout Int,<br />
and a function. It will extract the Int from that type and use it to<br />
bind "b".<br />
<br />
So in bindM (evalM_1 u) (\b ->) "b" will be bound to the value<br />
returned by evalM_1 u, and this bound variable will be available in<br />
what comes after "->" as a bound variable (not free).<br />
<br />
Then the outer part (bindM (evalM_1 t) (\a...) will bind "a" to the<br />
value returned "evalM_1 t", the result of the evaluatuion of the first<br />
Term. This value is needed to evaluate "((a+b), formatLine...) and<br />
produce our final MOut Int.<br />
<br />
We can try to explain "bindM" in a different way by using more descriptive names.<br />
<br />
As we have seen, "bindM" extracts the Int part from our type. The Int<br />
part will be used for further computations and the Output part will be<br />
concatenated. As a result we will have a new pair with a new Int and<br />
an accumulated Output.<br />
<br />
The new version of "bindM":<br />
<haskell><br />
<br />
> getIntFromType typeMOut doSomething = (newInt,oldOutput ++ newOutput)<br />
> where (oldInt,oldOutput) = typeMOut<br />
> (newInt,newOutput) = (doSomething oldInt)<br />
<br />
</haskell><br />
<br />
As you can see it does the very same things that "bindM" does: it<br />
takes something of type MOut and a function to perform some<br />
computation with the Int part. <br />
<br />
In the "where" clause, the old Int and the old output<br />
will be extracted from our type MOut (first line of the "where"<br />
clause). <br />
<br />
A new Int and a new output will be extracted from evaluating<br />
(doSomething oldInt) in the second line.<br />
<br />
Our function will return the new Int and the concatenated outputs.<br />
<br />
We do not need to define our doSomething function, because it will be<br />
an anonymous function:<br />
<br />
<haskell><br />
<br />
> evaluator (Con a) = (a, "output-")<br />
> evaluator (Add t u) = <br />
> getIntFromType (evaluator t) <br />
> (\firstInt -> getIntFromType (evaluator u) <br />
> (\secondInt -> ((firstInt + secondInt),("-newoutput"))))<br />
<br />
</haskell><br />
<br />
As you can see we are feeding our "getIntFromType" with the evaluation<br />
of an expression ("evaluator t" and "evaluator u"). The second<br />
argument of "getIntFromType" is an anonymous function that takes the<br />
"oldInt" and does something with it.<br />
<br />
So we have a series of nested anonymous functions. Their arguments<br />
("\firstInt" and "\secondInt") will be used to produce the computation<br />
we need ("(firstInt + secondInt). Moreover "getIntFromType" will take<br />
care of concatenating the outputs.<br />
<br />
This is the result:<br />
<br />
*TheMonadicWay> evaluator (Add (Con 5) (Con 6))<br />
(11,"output-output--newoutput")<br />
*TheMonadicWay> <br />
<br />
Going back to our "bindM", we can now use lambda notation to write our<br />
evaluator in a more convinient way:<br />
<br />
<haskell><br />
<br />
> evalM_2 :: Term -> MOut Int<br />
> evalM_2 (Con a) = (a, formatLine (Con a) a)<br />
> evalM_2 (Add t u) = evalM_2 t `bindM` \a -><br />
> evalM_2 u `bindM` \b -><br />
> ((a + b), (formatLine (Add t u) (a + b)))<br />
<br />
</haskell><br />
<br />
Now, look at the first part:<br />
<br />
<haskell><br />
evalM_2 (Con a) = (a, formatLine (Con a) a)<br />
</haskell><br />
<br />
We could use a more general way of creating some output. <br />
<br />
We can create a function that takes an Int and returns the type MOut<br />
Int. We do that by pairing the received Int with an empty string "".<br />
<br />
This will be a general way of creating an object with type MOut Int starting from an Int.<br />
<br />
Or, more generaly, a function that takes something of a variable type<br />
a, and return an object of type MOut a, a coumpunt object made up of<br />
an element of type a, and one of type String.<br />
<br />
There it is:<br />
<br />
<haskell><br />
<br />
> mkM :: a -> MOut a<br />
> mkM a = (a, "")<br />
<br />
</haskell><br />
<br />
As you can see, this function will just push an Int and an empty<br />
string ("") inside our type MOut.<br />
<br />
Then we need a method of inserting some text in our object of type<br />
MOut. So we will take a string and return it paired with a void<br />
element "()":<br />
<br />
<haskell><br />
<br />
> outPut :: Output -> MOut ()<br />
> outPut x = ((), x)<br />
<br />
</haskell><br />
<br />
Very simple: we have a string "x" (Output) and create a pair with a ()<br />
instead of an Int, and the output.<br />
<br />
You can see this function as one that pushes a string, paired with a<br />
void int, inside our type MOut.<br />
<br />
Now we can rewrite:<br />
<haskell><br />
evalM_2 (Con a) = (a, formatLine (Con a) a)<br />
</haskell><br />
using the bindM function:<br />
<haskell><br />
evalM_2 (Con a) = outPut (formatLine (Con a) a) `bindM` \_ -> mkM a<br />
</haskell><br />
<br />
First we create an object of type MOut with the Int part (). As you<br />
see bindM will not use it ("\_"), but will concatenate the String part<br />
with the result of mkM, which in turn is the empty string "".<br />
<br />
In other words, first we insert the Output part (a string) in our<br />
MOut, and then we insert the Int paired with an empty string: "bindM"<br />
will not use the void int (the anonymous function will not use it's<br />
argument: "\_"), but will take care of concatenating the non empty<br />
string inserted by "outPut" with the empty one inserted by "mkM".<br />
<br />
Let's rewrite the evaluator:<br />
<br />
<haskell><br />
<br />
> evalM_3 :: Term -> MOut Int<br />
> evalM_3 (Con a) = outPut (formatLine (Con a) a) `bindM` \_ -> <br />
> mkM a<br />
> evalM_3 (Add t u) = evalM_3 t `bindM` \a -><br />
> evalM_3 u `bindM` \b -><br />
> outPut (formatLine (Add t u) (a + b)) `bindM` \_ -> <br />
> mkM (a + b)<br />
<br />
</haskell><br />
<br />
Well, this is fine, definetly better then before, anyway.<br />
<br />
Still we use `bindM` \_ -> that binds something we do not use (_). We<br />
could write a function for this specific case, when we concatenate<br />
computations without the need of binding variables for later uses.<br />
Let's call it `combineM`:<br />
<br />
<haskell><br />
<br />
> combineM :: MOut a -> MOut b -> MOut b<br />
> combineM m f = m `bindM` \_ -> f<br />
<br />
</haskell><br />
<br />
This is just something that will allow us to write the evaluator in a<br />
more concise way. <br />
<br />
So the new evaluator:<br />
<br />
<haskell><br />
<br />
> evalM :: Term -> MOut Int<br />
> evalM (Con a) = outPut (formatLine (Con a) a) `combineM` <br />
> mkM a<br />
> evalM (Add t u) = evalM t `bindM` \a -><br />
> evalM u `bindM` \b -><br />
> outPut (formatLine (Add t u) (a + b)) `combineM` <br />
> mkM (a + b)<br />
<br />
</haskell><br />
<br />
Let's put everything together (changing M into MO, so that this file<br />
will be still usable as a Literate Haskell file):<br />
<br />
<haskell><br />
<br />
> type MO a = (a, Out)<br />
> type Out = String<br />
<br />
> mkMO :: a -> MO a<br />
> mkMO a = (a, "")<br />
<br />
> bindMO :: MO a -> (a -> MO b) -> MO b<br />
> bindMO m f = (b, x ++ y)<br />
> where (a, x) = m<br />
> (b, y) = f a<br />
<br />
> combineMO :: MO a -> MO b -> MO b<br />
> combineMO m f = m `bindM` \_ -> f<br />
<br />
> outMO :: Out -> MO ()<br />
> outMO x = ((), x)<br />
<br />
> evalMO :: Term -> MO Int<br />
> evalMO (Con a) = outMO (formatLine (Con a) a) `combineMO`<br />
> mkMO a<br />
> evalMO (Add t u) = evalMO t `bindMO` \a -><br />
> evalMO u `bindMO` \b -><br />
> outMO (formatLine (Add t u) (a + b)) `combineMO` <br />
> mkMO (a + b)<br />
<br />
</haskell><br />
<br />
==What does bind bind?==<br />
<br />
<div id="Bind"><br />
The evaluator looks like:<br />
<haskell><br />
evalM t >>= \a -> evalM u >>= \b -> outPut "something" >>= \_ -> mkM (a +b)<br />
</haskell><br />
where >>= is bindMO, obviously.<br />
<br />
Let's do some substitution, writing the type of their output of each function:<br />
* evalMO t => (a,Out) - where a is Int<br />
* evalMO u => (b,Out) - where b is the same of a, an Int, but with a different value<br />
* outMO Out = ((),Out)<br />
* mkMO (a+b) => ((a+b),Out) - where (a+b) is the same of a and b, but with a different value from either a and b<br />
<br />
<pre><br />
B | (a,Out) >>= \a -> (b,Out) >>= \b -> ((),Out) >>= \_ >>= ((a + b), Out)---\<br />
i | V V V V V V V V ^ ^ ^ ^ |\<br />
n | |__|________^ | | ^ | | | | | | | MOut Int <=> ((a+b), Out)<br />
d |_____|__(++)__|_Out_|__|__(++)__V_Out_|___|___(++)_|_(++)__|___|____|_____|/<br />
i | | |______(b)__|_____|_____(b)____|__(b)__|___|<br />
n | |_________(a)___________|____________|__(a)__|<br />
g | |_____()_____|<br />
<br />
</pre><br />
<br />
Clear, isn't it?<br />
<br />
"bindMO" is just a function that takes care of gluing together, inside<br />
a data type, a sequence of computations!<br />
<br />
== Some sugar, please!==<br />
Now our evaluator has been completely transformed into a monadic<br />
evaluator. That's what it is: a monad.<br />
<br />
We have a function that constructs an object of type MO Int, formed by<br />
a pair: the result of the evaluation and the accumulated<br />
(concatenated) output.<br />
<br />
The process of accumulation and the act of parting the MO Int into its<br />
component is buried into bindMO, now, that can also preserve some<br />
value for later uses.<br />
<br />
So we have:<br />
* MO a type constructor for a type carrying a pair composed by an Int and a String;<br />
* bindMO, that gives a direction to the process of evaluation: it concatenates computations and captures some side effects we created (the direction is given by the changes in the Out part: there's a "before" when Out was something and there's a "later" when Out is something else).<br />
* mkMO lets us create an object of type MO Int starting from an Int.<br />
<br />
As you see this is all we need to create a monad. In other words<br />
monads arise from the type system and the lambda calculus. Everything<br />
else is just syntactic sugar.<br />
<br />
So, let's have a look at that sugar: the famous do-notation!<br />
<br />
===Monadic evaluator with output in do-notation===<br />
<br />
In order to be able to use the "do-notation" we need to define a new<br />
type and make it an instance of the Monad class. To make a new type an<br />
instance of the Monad class we will have to define the two methods of<br />
this class: (>>=) and "return".<br />
<br />
This is not going to be difficult, because we already created these<br />
two methods: "bindM" and "mkM". Now we will have to rewrite them in<br />
order to reflect the fact that we are not going to use a type, for our<br />
evaluator, that is a synonymous of other types, as we did before.<br />
Indeed our MOut was defined with the "type" keyword. Now we will have<br />
to define a "real" new type with either "newtype" or "data". Since we<br />
are not going to need multiple constructors, we will use "newtype".<br />
<br />
<div id="MonadicEvalIO"><br />
<haskell><br />
<br />
> newtype Eval_IO a = Eval_IO (a, O)<br />
> deriving (Show)<br />
> type O = String<br />
<br />
</haskell><br />
<br />
This is our new type: it will have a single type constructor, whose<br />
name is the same of the type name ("Eval_IO"). The type constructor<br />
takes a parameter ("a"), a variable type, and will build a type formed<br />
by a type "a" (an Int in our case) and a String (O is indeed<br />
synonymous of String).<br />
<br />
We now need to define our "bind" function to reflect the fact that we<br />
are now using a "real" type, and, to unpack its content, we need to do<br />
pattern-matching we the type constructor "Eval_IO". Moreover, since we<br />
must return an Eval_IO type, we will use the type constructor also for<br />
building the new type with the new int and the concatenated output.<br />
<br />
For the rest our "bind" function will be identical to the one we<br />
defined before.<br />
<br />
We are going to use very descriptive names:<br />
<br />
<haskell><br />
<br />
> getInt monad doSomething = Eval_IO (newInt,oldOutput ++ newOutput)<br />
> where Eval_IO (oldInt,oldOutput) = monad<br />
> Eval_IO (newInt,newOutput) = (doSomething oldInt)<br />
<br />
</haskell><br />
<br />
As you can see, we are using Eval_IO to build the result of the<br />
computation to be returned by getInt: "Eval_IO (newInt,oldOutput ++<br />
newOutput)". And we are using it to match the internal components of<br />
our type in the "where" clause.<br />
<br />
We also need to create a function that, like mkO, will take an Int and,<br />
using the type constructor "Eval_IO", will create an object of type<br />
Eval_IO with that Int and an empty string:<br />
<br />
<haskell><br />
<br />
> createEval_IO :: a -> Eval_IO a<br />
> createEval_IO int = Eval_IO (int,"")<br />
<br />
</haskell><br />
<br />
And, finally, we need a function that will insert, in our type, a<br />
string and a void ():<br />
<br />
<haskell><br />
<br />
> print_IO :: O -> Eval_IO ()<br />
> print_IO string = Eval_IO ((), string)<br />
<br />
</haskell> <br />
<br />
With these functions we could write our monadic evaluator without the<br />
"do-notation" like this:<br />
<br />
<haskell><br />
<br />
> evalM_4 :: Term -> Eval_IO Int<br />
> evalM_4 (Con a) = createEval_IO a<br />
> evalM_4 (Add t u) = evalM_4 t `getInt` \a -><br />
> evalM_4 u `getInt` \b -><br />
> print_IO (formatLine (Add t u) (a + b)) `getInt` \_ -><br />
> createEval_IO (a + b)<br />
<br />
</haskell><br />
<br />
It is very similar to the previous evaluator, as you can see. The only<br />
differences are related to the fact that we are now using a "real"<br />
type and not a type synonymous: this requires the use of the type<br />
constructor to match the type and its internal part (as we do in the<br />
"where" clause of our "bind" function: "getInt") or to build the type<br />
(as we do in the "bind" function to return the new Int with the<br />
concatenated output).<br />
<br />
Running this evaluator will produce:<br />
<br />
*TheMonadicWay> evalM_4 (Add (Con 6) (Con 12))<br />
Eval_IO (18,"eval (Add (Con 6) (Con 12)) <= 18 - ")<br />
*TheMonadicWay> <br />
<br />
Now we have everything we need to declare our type, Eval_IO, as an<br />
instance of the Monad class:<br />
<haskell><br />
<br />
> instance Monad Eval_IO where<br />
> return a = createEval_IO a<br />
> (>>=) m f = getInt m f<br />
<br />
</haskell><br />
<br />
As you see we are just using our defined functions as methods for our<br />
instance of the Monad class.<br />
<br />
This is all we need to do. Notice that we do not have to define the<br />
"combineM" function, for chaining computation, as we do with "getInt",<br />
without binding variables for later use within the series of nested<br />
anonymous functions (the "doSomething" part) that will form the "do"<br />
block.<br />
<br />
This function comes for free by just defining our type as an instance<br />
of the Monad class. Indeed, if you look at the definition of the Monad<br />
class in the Prelude you see that "combineM", or (>>) is deduced by<br />
the definition of (>>=):<br />
<br />
<haskell><br />
class Monad m where<br />
return :: a -> m a<br />
(>>=) :: m a -> (a -> m b) -> m b<br />
(>>) :: m a -> m b -> m b<br />
fail :: String -> m a<br />
<br />
-- Minimal complete definition: (>>=), return<br />
p >> q = p >>= \ _ -> q<br />
fail s = error s<br />
</haskell><br />
<br />
You can see that the "combineM"" method (or (>>)) is automatically<br />
derived by the "bindMO" (or >>=) method:<br />
<br />
<haskell><br />
p >> q = p >>= \ _ -> q<br />
</haskell><br />
<br />
We can now write our evaluator using the do-notation:<br />
<br />
<haskell><br />
<br />
> eval_IO :: Term -> Eval_IO Int<br />
> eval_IO (Con a) = do print_IO (formatLine (Con a) a)<br />
> return a<br />
> eval_IO (Add t u) = do a <- eval_IO t<br />
> b <- eval_IO u<br />
> print_IO (formatLine (Add t u) (a + b))<br />
> return (a + b)<br />
<br />
</haskell><br />
<br />
As you can see the anonymous functions are gone. Instead we use this:<br />
a <- eval_IO t<br />
<br />
This seems like an assignment, that cannot be possible in Haskell. In<br />
fact it is just the way our anonymous function's arguments is bound<br />
within a do block.<br />
<br />
Even if it does not seem like a series of nested anonymous functions,<br />
this is what actually a do block is.<br />
<br />
Our monad is defined by three elements: <br />
* a type, with its type constructor(s);<br />
* a bind method: it will bind an unwritten anonymous function's argument to the value of the Int part of our type, or more generally, of the variable type "a". It will also create a series of anonymous functions: a line for each function;<br />
* a "return" function, to insert, into out type, a value of type Int, or, more generally, a value of variable type "a".<br />
<br />
Additionally, we need a function to insert a string in our type,<br />
string that the derived "bind" (>>) will concatenate ignoring the void<br />
(), our "print_IO".<br />
<br />
Within a do block we can thus perform only tree kinds of operations:<br />
* a computation that produces a new Int, packed inside our monad's type, to be extracted and bound to a variable (an anonymous function's argument really):<br />
** this operation requires a binding (">>= \varName ->"), translated into "varName <- computation"<br />
** example: a <- eval_IO t<br />
* a computation that inserts a string into our monad, a string to be concatenated, without the need of binding a variable (an anonymous function's argument really):<br />
** this operation does not require a binding: it will be ">>= \_ ->", i.e. ">>", translated into a simple new line<br />
** example: print_IO (formatLine (Add t u) (a + b))<br />
* a computation that inserts an Int into our monad without the need of binding a variable (an anonymous function's argument really):<br />
** this operation is carried out by the <hask>return</hask> method (usually at the end of a do block, useless in the middle)<br />
** example <hask>return (a + b)</hask><br />
<br />
To sum up, within a block, "do" will take care of creating and<br />
nesting, for us, all the needed anonymous functions so that bound<br />
variables will be available for later computations.<br />
<br />
In this way we can emulate a direction of our computation, a "before"<br />
and an "after", even within a pure functional language. And we can use<br />
this possibility to create and accumulate side effects, like output.<br />
<br />
Let's see the evaluator with output in action:<br />
*TheMonadicWay> eval_IO (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <br />
Eval_IO (54,"eval (Con 6) <= 6 - eval (Con 16) <= 16 - eval (Con 20) <= 20 - eval (Con 12) <= 12 - \<br />
eval (Add (Con 20) (Con 12)) <= 32 - eval (Add (Con 16) (Add (Con 20) (Con 12))) <= 48 - \<br />
eval (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <= 54 - ")<br />
*TheMonadicWay> <br />
<br />
Let's format the output part:<br />
eval (Con 6) <= 6 <br />
eval (Con 16) <= 16 <br />
eval (Con 20) <= 20 <br />
eval (Con 12) <= 12 <br />
eval (Add (Con 20) (Con 12)) <= 32 <br />
eval (Add (Con 16) (Add (Con 20) (Con 12))) <= 48 <br />
eval (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <= 54 <br />
<br />
==[[Type]] and [[Newtype]]: What happened to our output?==<br />
<br />
Well, actually something happened to the output. Let's compare the<br />
output of evalMO (the monadic evaluator written without the<br />
do-notation) and eval_IO:<br />
<br />
*TheMonadicWay> evalMO (Con 6)<br />
(6,"eval (Con 6) <= 6 - ")<br />
*TheMonadicWay> eval_IO (Con 6)<br />
Eval_IO (6,"eval (Con 6) <= 6 - ")<br />
*TheMonadicWay> <br />
<br />
They look almost the same, but they are not the same: the output of<br />
eval_IO has the Eval_IO stuff. It must be related to the changes we<br />
had to do to our evaluator in order to use the do-conation, obviously.<br />
<br />
We can now review some of our basic knowledge of Haskell's type<br />
system.<br />
<br />
What's changed? First the type definition. We have now:<br />
<br />
<haskell><br />
newtype Eval_IO a = Eval_IO (a, O)<br />
deriving (Show)<br />
</haskell><br />
<br />
instead of <br />
<br />
<haskell><br />
type MO a = (a, Out)<br />
</haskell><br />
<br />
Now <hask>return a</hask> is the product of the application of the<br />
type constructor Eval_IO to the pair that are going to form our monad.<br />
<br />
"return" takes an Int and inserts it into our monad. It will also<br />
insert an empty String "" that (>>=) or (>>) will then concatenate in<br />
the sequence of computations they glue together.<br />
<br />
The same for (>>=). It will now return something constructed by<br />
Eval_IO: <br />
<br />
* "newInt", the result of the application of "doSomething" to "oldInt" (better, the binding of "oldInt" in "doSomething");<br />
* the concatenation of "oldOutput" (matched by <hask>Eval_IO (oldInt, oldOutput)</hask> with the evaluation of "monad" - "eval_IO t") and "newOutput", (matched by "Eval_IO(newInt,newOutput)" with the evaluation of "(doSomething monad)" - "eval_IO u").<br />
<br />
That is to say: in the "where" clause, we are matching for the<br />
elements paired in a type Eval_IO: this is indeed the type of "monad"<br />
(corresponding to "eval_IO t" in the body of the evaluator) and<br />
"(doSomething monad)" (where "doSomething" correspond to the<br />
evaluation of "eval_IO u" within an anonymous function with \oldInt as<br />
its argument, argument bound to the result of the previous evaluation<br />
of "monad", that is to say "eval_IO t").<br />
<br />
And so, "Eval_IO (oldInt,oldOutput) = monad" means: match "oldInt" and<br />
"oldOutput", paired in a type Eval_IO, and that are produced by the<br />
evaluation of "monad" (that is to say: "eval_IO t"). The same for<br />
Eval_IO (newInt,newOutput): match "newInt" and "newOutput" produced by<br />
the evaluation of "(doSomething monad)".<br />
<br />
So the output of the evaluator is now not simply a pair made of and<br />
Int and a String. It is a specific type (Eval_IO) that happens to<br />
carry a pair of an Int and a String. But, if we want the Int and the<br />
string, we have to extract them from the Eval_IO type, as we do in the<br />
"where" clause: we ''unpack'' our type object (let's call it with its<br />
name: our monad!) and take out the Int and the String to feed the next<br />
function application and the output generation.<br />
<br />
The same to insert something in our monad: if we want to create a pair<br />
of an Int and a String, pair of type Eval_IO, we now have to ''pack''<br />
them together by using our type constructor, feeding it with a pair<br />
composed by and Int and a String. This is what we do with the "return"<br />
method of out monad and with "print_IO" function, where:<br />
* return insert into the monad an Int;<br />
* print_IO insert into the monad a String.<br />
<br />
So, why cannot we use the old <hask>type MO a = (a, Out)</hask> that<br />
did not required all this additional work (apart the need to<br />
specifically define (>>)?<br />
<br />
Type MO is just a synonymous for (a,Out): the two can be substituted<br />
one for the other. That's it.<br />
<br />
We did not have to pack "a" and "Out" together with a type constructor<br />
to have a new type MO.<br />
<br />
As a consequence, we cannot use MO as an instance of Monad, and so, we<br />
cannot use with it the syntactic sugar we needed: the do-notation.<br />
<br />
That is to say: a type created with the "type" keyword cannot be an<br />
instance of a class, and cannot inherits its methods (in our case<br />
(>>=, >> and return). And without those methods the do-notation is not<br />
usable.<br />
<br />
==Errare monadicum est==<br />
<br />
Now that we have a basic understanding of what a monad is, and does,<br />
we will further explore it by making some changes to our evaluator.<br />
<br />
In this section we will se how to handle exceptions in our monadic<br />
evaluator.<br />
<br />
Suppose that we want to stop the execution of our monad if some<br />
conditions occurs. If our evaluator was to compute divisions, instead<br />
of sums, then we would like to stop the evaluator when a division by<br />
zero occurs, possibly producing some output, instead of the result of<br />
the evaluation of the expression, that explains what happened.<br />
<br />
Basic error handling.<br />
<br />
We will do so starting from the beginning once again...<br />
<br />
===The basic evaluator, non monadic, with exception===<br />
<br />
We just take our basic evaluator, without any output, and write a<br />
method to stop execution if a condition occurs: <br />
<br />
<haskell><br />
<br />
> data M a = Raise Exception<br />
> | Return a<br />
> deriving (Show)<br />
> type Exception = String<br />
<br />
</haskell><br />
<br />
Now, our monad is of datatype "M a" which can either be constructed<br />
with the "Raise" constructor, that takes a String (Exception is a<br />
synonymous of String), or by the "Return" constructor, that takes a<br />
variable type ("a"), an Int in our case.<br />
<br />
<haskell><br />
<br />
> evalE :: Term -> M Int<br />
> evalE (Con a) = Return a<br />
<br />
</haskell><br />
<br />
If evalE matches a Con it will construct a type Return with, inside, the content of the Con.<br />
<br />
<haskell><br />
<br />
> evalE (Add a b) = <br />
> case evalE a of<br />
> Raise e -> Raise e<br />
> Return a -><br />
> case evalE b of <br />
> Raise e -> Raise e<br />
> Return b -><br />
> if (a+b) == 42<br />
> then Raise "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else Return (a+b)<br />
<br />
</haskell><br />
<br />
If evalE matches an Add it will check if evaluating the first part<br />
produces a "Raise" or a "Return": in the first case it will return a<br />
"Raise" whose content is the same received. <br />
<br />
If instead the evaluation produces a value of a type matched by<br />
"Return", the evaluator will evaluate the second term of Add.<br />
<br />
If this returns a "Raise", a "Raise" will be returned all the way up<br />
the recursion, otherwise the evaluator will check whether a condition<br />
for raising a "Raise" exists. If not, it will return a "Return" with<br />
the sum inside.<br />
<br />
Test it with:<br />
<br />
evalE (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2)))<br />
<br />
<br />
===The basic evaluator, monadic, with exceptions===<br />
<br />
In order to produce a monadic version of the previous evaluator, the<br />
one that raises exceptions, we just need to abstract out from the<br />
evaluator all that case analysis.<br />
<br />
<haskell><br />
<br />
> data M1 a = Except Exception<br />
> | Ok {showM :: a }<br />
> deriving (Show)<br />
<br />
</haskell><br />
<br />
The data type didn't change at all. Well, we changed the name of the<br />
Return type constructor (now Ok) so that this constructor can coexist<br />
with the previous one in the same Literate Haskell file.<br />
<br />
<div id="MonadicEvalE"><br />
<haskell><br />
<br />
> instance Monad M1 where<br />
> return a = Ok a<br />
> m >>= f = case m of<br />
> Except e -> Except e<br />
> Ok a -> f a<br />
<br />
</haskell><br />
<br />
Binding operations are now very easy. Basically we check:<br />
* if the result of the evaluation of "m" produces an exception (first match: Except e ->...), in which case we return its content by constructing our M1 Int with the "Raise" constructor".<br />
* if the result of the evaluation of "m" is matched with the "Ok" constructor, we get its content and use it to bind the argument of "f" to its value.<br />
<br />
<hask>return a</hask> will just use the Ok type constructor for<br />
inserting "a" (in our case an Int) into M1 Int, the type of our monad.<br />
<br />
<haskell><br />
<br />
> raise :: Exception -> M1 a<br />
> raise e = Except e<br />
<br />
</haskell><br />
<br />
This is just a helper function to construct our "M1 a" type with the<br />
Raise constructor. It takes a string and returns a type (M1 a) to be<br />
matched with the "Raise" constructor.<br />
<br />
<haskell><br />
<br />
> eval_ME :: Term -> M1 Int<br />
> eval_ME (Con a) = do return a<br />
> eval_ME (Add t u) = do a <- eval_ME t<br />
> b <- eval_ME u<br />
> if (a+b) == 42<br />
> then raise "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
</haskell><br />
<br />
The evaluator itself is very simple. We bind "a" with the result of<br />
"eval_ME t", "b" with the result of "eval_ME u", and we check for a<br />
condition: <br />
* if the condition is met we raise an exception, that is to say: we return a value constructed with the "Raise" constructor. This value will be matched by ">>=" in the next recursion. And >>= will just return it all the way up the recursion.<br />
* if the condition is not met, we return a value constructed with the "Return" type constructor and go on with the recursion.<br />
<br />
Run with:<br />
<br />
eval_ME (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2)))<br />
<br />
It is noteworthy the fact that in our datatype definition we used a<br />
label field with a label selector (we called it showM), even though it<br />
was not used in our code. We will use this methodology later on.<br />
<br />
So, just to refresh your memory:<br />
<br />
<haskell><br />
<br />
> data Person = Person {name :: String,<br />
> age :: Int,<br />
> hobby :: String<br />
> } deriving (Show)<br />
<br />
> andreaRossato = Person "Andrea" 37 "Haskell The Monadic Way"<br />
> personName (Person a b c) = a<br />
<br />
</haskell><br />
<br />
will produce:<br />
*TheMonadicWay> andreaRossato<br />
Person {name = "Andrea", age = 37, hobby = "Haskell The Monadic Way"}<br />
*TheMonadicWay> personName andreaRossato<br />
"Andrea"<br />
*TheMonadicWay> name andreaRossato<br />
"Andrea"<br />
*TheMonadicWay> age andreaRossato<br />
37<br />
*TheMonadicWay> hobby andreaRossato<br />
"Haskell The Monadic Way"<br />
*TheMonadicWay> <br />
<br />
<br />
===Monadic evaluator with output and exceptions===<br />
<br />
We will now try to combine the [[The Monadic Way/Part I#MonadicEvalIO|output-producing monadic evaluator]] <br />
with [[The Monadic Way/Part I#MonadicEvalE| exception producing one]].<br />
<br />
<br />
<haskell><br />
<br />
> data M2 a = Ex Exception<br />
> | Done {unpack :: (a,O) }<br />
> deriving (Show)<br />
<br />
</haskell><br />
<br />
Now we need a [[algebraic datatype]] with two [[constructor]]s: one to produce a value type "M2 a" using "Ex String" and one for value type "M2 a" (Int in<br />
this case) using "Done a".<br />
<br />
'''Note''' that we changed the name of the exception type constructor<br />
from "Raise" to "Ex" just to make the two coexist in the same [[Literate programming|literate Haskell]] file.<br />
<br />
The constructor "Done a" is defined with a label selector: <hask>Done {unpack :: (a,O)}</hask> <br />
and is equivalent to <hask>Done (a,O)</hask>. <br />
<br />
The only difference is that, this way, we are also defining a method<br />
to retrieve the pair (a,O) (in our case "O" is a synonymous for<br />
String, whereas "a" is a variable type) from an object of type "Done<br />
a".<br />
<br />
<haskell><br />
<br />
> instance Monad M2 where<br />
> return a = Done (a, "")<br />
> m >>= f = case m of<br />
> Ex e -> Ex e<br />
> Done (a, x) -> case (f a) of<br />
> Ex e1 -> Ex e1<br />
> Done (b, y) -> Done (b, x ++ y)<br />
<br />
</haskell><br />
<br />
Now our binding operations gets more complicated by the fact that we<br />
have to concatenate the output, as we did before, '''and''' check for<br />
exceptions.<br />
<br />
It is not possible to do has we did in the [[The Monadic Way/Part I#MonadicEvalE| exception producing evaluator]], <br />
where we could check just for "m" (remember the "m" in the first run<br />
stands for "eval t").<br />
<br />
Since at the end we must return the output produced by the evaluation<br />
of "m" ''concatenated'' with the output produced by the evaluation of<br />
"f a" (where "a" is returned by "m", paired with "x" by "Done"), now<br />
we must check if we '''do have''' an output from "f a" produced by<br />
"Done".<br />
<br />
Indeed, now, "f a" can also produce a value constructed by "Ex", and<br />
this value does not contain the pair as the value produced by "Done".<br />
<br />
So, we evaluate "m": <br />
* if we match a value produced by type constructor "Ex" we return a value produced by type constructor "Ex" whose content is the one we extracted in the matching;<br />
* if we match a value produced by "Done" we match the pair it carries "(a,x)" and we analyze what "f a" returns:<br />
** if "f a" returns a value produced by "Ex" we extract the exception and we return it, constructing a value with "Ex"<br />
** if "f a" returns a value produced by "Done" we return "b" and the concatenated "x" and "y". <br />
<br />
And now the evaluator:<br />
<br />
<haskell><br />
<br />
> raise_IOE :: Exception -> M2 a<br />
> raise_IOE e = Ex e<br />
<br />
</haskell><br />
<br />
This is the [[function]] to insert an exception in our monad (M2): We take<br />
a String and produce a value applying the type constructor for exception "Ex" to its value.<br />
<br />
<haskell><br />
<br />
> print_IOE :: O -> M2 ()<br />
> print_IOE x = Done ((), x)<br />
<br />
</haskell><br />
<br />
The function to produce output is the very same of the one of the [[The Monadic Way/Part I#MonadicEvalIO|output-producing monadic evaluator]].<br />
<br />
<haskell><br />
<br />
> eval_IOE :: Term -> M2 Int<br />
> eval_IOE (Con a) = do print_IOE (formatLine (Con a) a)<br />
> return a<br />
> eval_IOE (Add t u) = do a <- eval_IOE t<br />
> b <- eval_IOE u<br />
> let out = formatLine (Add t u) (a + b)<br />
> print_IOE out<br />
> if (a+b) == 42<br />
> then raise_IOE $ out ++ "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
</haskell><br />
<br />
The evaluator procedure did not change very much from the one of the [[The Monadic Way/Part I#MonadicEvalIO|output-producing monadic evaluator]].<br />
<br />
We just added the case analysis to see if the condition for raising an exception is met.<br />
<br />
Running with<br />
<br />
eval_IOE (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2)))<br />
<br />
will produce <br />
<br />
Ex "eval (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2))) <= 42 - <br />
The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
<br />
Look at the <hask>let</hask> clause within the do-notation. We do not<br />
need to use the "let ... in" construction: since all [[bound variable]]s<br />
remain bound within a <hask>do</hask> procedure (see [[The Monadic Way/Part I#Bind|here]]), <br />
we do not need the "in" to specify "where" the variable "out" will be bound in!<br />
<br />
==We need a state==<br />
<br />
We will keep on adding complexity to our monadic evaluator and this<br />
time we will add a counter. We just want to count the number of<br />
iterations (the number of times "eval" will be called) needed to<br />
evaluate the expression.<br />
<br />
===The basic evaluator, non monadic, with a counter===<br />
<br />
As before we will start by adding this feature to our [[The Monadic Way Part I#BasicEval|basic evaluator]]. <br />
<br />
A method to count the number of iterations, since the lack of<br />
assignment and destructive updates (such as for i=0;i<10;i++;),<br />
is to add an argument to our function, the initial state, number that<br />
in each call of the function will be increased and passed to the next<br />
function call.<br />
<br />
And so, very simply:<br />
<br />
<haskell><br />
<br />
> -- non monadic<br />
> type St a = State -> (a, State)<br />
> type State = Int<br />
> evalNMS :: Term -> St Int<br />
> evalNMS (Con a) x = (a, x + 1)<br />
> evalNMS (Add t u) x = let (a, y) = evalNMS t x in<br />
> let (b, z) = evalNMS u y in<br />
> (a + b, z +1)<br />
<br />
</haskell><br />
<br />
Now evalNMS takes two arguments: the expression of type Term and an<br />
State (which is a synonymous for Int), and will produce a pair<br />
(a,State), that is to say a pair with a variable type "a" and an Int.<br />
<br />
The operations in the evaluator are very similar to the non monadic [[The Monadic Way Part I#BasivEvalO|output producing evaluator]].<br />
<br />
We are now using the "let ... in" clause, instead of the "where", and we are increasing the counter "z" the comes from the evaluation of the second term, but the basic operation are the same:<br />
* we evaluate "evalNMS t x" where "x" is the initial state, and we match and bind the result in "let (a, y) ... in"<br />
* we evaluate "evalNMS u y", where "y" was bound to the value returned by the previous evaluation, and we match and bind the result in "let (b, z) ... in"<br />
* we return a pair formed by the sum of the result (a+b) and the state z increased by 1. <br />
<br />
Let's try it:<br />
<br />
*TheMonadicWay> evalNMS (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2))) 0<br />
(42,7)<br />
*TheMonadicWay> <br />
<br />
As you see we must pass to "evalNMS"the initial state of our counter: 0.<br />
<br />
Look at the type signature of the function "evalNMS":<br />
<haskell><br />
evalNMS :: Term -> St Int<br />
</haskell><br />
<br />
From this signature you could argue that our function takes only<br />
'''one''' argument. But since our type St is defined with the "type"<br />
keyword, St can be substituted with what comes after the "=" sign. So,<br />
the real type signature of our function is:<br />
<br />
<haskell><br />
evalNMS :: Term -> State -> (Int,State)<br />
</haskell><br />
<br />
<div if="typeNewtype"><br />
Just to refresh your memory:<br />
<br />
<haskell><br />
<br />
> type IamAfunction a = (a -> a)<br />
> newtype IamNotAfunction a = NF (a -> a)<br />
> newtype IamNotAfunctionButYouCanUnPackAndRunMe a = F { unpackAndRun :: (a -> a) }<br />
<br />
> a = \x -> x * x<br />
<br />
> a1 :: IamAfunction Integer<br />
> a1 = a<br />
<br />
> a2 :: IamNotAfunction Integer<br />
> a2 = NF a<br />
<br />
> a3 :: IamNotAfunctionButYouCanUnPackAndRunMe Integer<br />
> a3 = F a<br />
<br />
</haskell><br />
<br />
<br />
*TheMonadicWay> a 4<br />
16<br />
*TheMonadicWay> a1 4<br />
16<br />
*TheMonadicWay> a2 4<br />
<br />
<interactive>:1:0:<br />
The function `a2' is applied to one arguments,<br />
but its type `IamNotAfunction Int' has only 0<br />
In the definition of `it': it = a2 4<br />
*TheMonadicWay> a3 4<br />
<br />
<interactive>:1:0:<br />
The function `a3' is applied to one arguments,<br />
but its type `IamNotAfunctionButYouCanUnPackAndRunMe Int' has only 0<br />
In the definition of `it': it = a3 4<br />
*TheMonadicWay> unpackAndRun a3 4<br />
16<br />
*TheMonadicWay><br />
<br />
This means that "a1" is a partial application hidden by a type<br />
synonymous. <br />
<br />
"a2" and "a3" are not function types. They are types that<br />
have a functional value. <br />
<br />
Moreover, since we defined the type constructor of type<br />
"IamNotAfunctionButYouCanUnPackAndRunMe", F, with a label field, in<br />
that label field we defined a method (a label selector) to "extract"<br />
the function from the type "IamNotAfunctionButYouCanUnPackAndRunMe",<br />
and run it:<br />
<br />
<haskell><br />
unpackAndRun a3 4<br />
</haskell><br />
<br />
And what about "a2"? Is it lost forever?<br />
<br />
Obviously not! We need to write a function that unpacks a type<br />
"IamNotAfunction", using its type constructor NF to match the internal<br />
function:<br />
<br />
<haskell><br />
<br />
> unpackNF :: IamNotAfunction a -> a -> a<br />
> unpackNF (NF f) = f<br />
<br />
</haskell><br />
<br />
and run:<br />
<br />
*TheMonadicWay> unpackNF a2 4<br />
16<br />
*TheMonadicWay> <br />
<br />
As you see, "unpackNF" definition is a partial application: we specify<br />
one argument to get a function that gets another argument.<br />
<br />
A label selector does the same thing.<br />
<br />
Later we will see the importance of this distinction, quite obvious<br />
for haskell gurus, but not for us. Till now.<br />
<br />
===The evaluator, monadic, with a counter===<br />
<br />
We will now rewrite our basic evaluator with the counter in<br />
do-notation.<br />
<br />
As we have seen, in order to do so we need:<br />
* a new type that we must declare as an instance of the Monad class;<br />
* a function for binding method (>>=) and a function for the "return" method, for the instance declaration; <br />
<br />
Now our type will be holding a function that will take the initial<br />
state 0 as we did before.<br />
<br />
In order to simplify the process of unpacking the monad each time to<br />
get the function, we will use a label sector:<br />
<br />
<haskell><br />
<br />
> newtype MS a = MS { unpackMSandRun :: (State -> (a, State)) }<br />
<br />
</haskell><br />
<br />
This is it: MS will be our type constructor for matching and for<br />
building our monad. "unpackMSandRun" will be the method to get the<br />
function out of the monad to feed it with the initial state of the<br />
counter, 0, to get our result.<br />
<br />
Then we need the "return" function that, as we have seen does nothing<br />
but inserting into our monad an Integer:<br />
<br />
<haskell><br />
<br />
> mkMS :: a -> MS a<br />
> mkMS int = MS (\x -> (int, x))<br />
<br />
</haskell><br />
<br />
"mkMS" will just take an Integer "a" and apply the MS type constructor<br />
to our anonymous function that takes an initial state and produces the<br />
final state "x" and the integer "a".<br />
<br />
In other words, we are just creating our monad with inside an Integer.<br />
<br />
Our binding function will be a bit more complicated then before. We<br />
must create a type that holds an anonymous function with elements to<br />
be extracted from our type and passed to the anonymous function that<br />
comes next:<br />
<br />
<haskell><br />
<br />
> bindMS :: MS a -> (a -> MS b) -> MS b<br />
> bindMS monad doNext = MS $ \initialState -> <br />
> let (oldInt, oldState) = unpackMSandRun monad initialState in<br />
> let (newInt, newState) = unpackMSandRun (doNext oldInt) oldState in<br />
> (newInt,newState)<br />
<br />
</haskell><br />
<br />
So, we are creating an anonymous function that will take an initial<br />
state, 0, and return a "newInt" and "newState". <br />
<br />
To do that we need to unpack and run our "monad" against the<br />
initialState in order to get the "oldInt" and the "oldState".<br />
<br />
The "oldInt" will be passed to the "doNext" function (the next<br />
anonymous function in our do block) together with the "oldState" to<br />
get the "newInt" and the "newState".<br />
<br />
We can now declare our type "MS" as an instance of the Monad class:<br />
<haskell><br />
<br />
> instance Monad MS where<br />
> return a = mkMS a<br />
> (>>=) m f = bindMS m f<br />
<br />
</haskell><br />
<br />
We now need a function to increase the counter in our monad from<br />
within a do block:<br />
<br />
<haskell><br />
<br />
> incState :: MS ()<br />
> incState = MS (\s -> ((), s + 1))<br />
<br />
</haskell><br />
<br />
This is easier then it looks like. We use the type constructor MS to<br />
create a function that takes a state an returns a void integer ()<br />
paired with the state increased by one. We do not need any binding,<br />
since we are just modifying the state, an integer, and, in our do<br />
block, we will insert this function before a new line, so that the non<br />
binding ">>" operator will be applied.<br />
<br />
And now the evaluator:<br />
<br />
<haskell><br />
<br />
> evalMS :: Term -> MS Int<br />
> evalMS (Con a) = do incState<br />
> mkMS a<br />
> evalMS (Add t u) = do a <- evalMS t<br />
> b <- evalMS u<br />
> incState <br />
> return (a + b)<br />
<br />
</haskell><br />
<br />
Very easy: we just added the "incState" function before returning the<br />
sum of the evaluation of the Terms of our expression.<br />
<br />
Let's try it:<br />
<br />
*TheMonadicWay> unpackMSandRun (evalMS (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12))))) 0<br />
(54,7)<br />
*TheMonadicWay> <br />
<br />
As you can see, adding a counter makes our binding operations a bit<br />
more complicated by the fact that we have an anonymous function within<br />
our monad. This means that we must recreate that anonymous function in<br />
each step of our do block. This makes "incState" and, as we are going<br />
to see in the next paragraph, the function to produce output a bit<br />
more complicated. Anyway we can handle this complexity quite well, for<br />
now.<br />
<br />
===The monadic evaluator with output and counter in do-notation===<br />
<br />
Adding output to our evaluator is now quite easy. It's just a matter<br />
of adding a field to our type, where we are going to accumulate the<br />
output, and take care of extracting it in our bind function to<br />
concatenate the old one with the new one.<br />
<br />
<haskell><br />
<br />
> newtype Eval_SIO a = Eval_SIO { unPackMSIOandRun :: State -> (a, State, Output) }<br />
<br />
</haskell><br />
<br />
Now our monad contains an anonymous function that takes the initial<br />
state, 0, and will produce the final Integer, the final state and the<br />
concatenated output.<br />
<br />
So, this is bind:<br />
<br />
<haskell><br />
<br />
> bindMSIO monad doNext = <br />
> Eval_SIO (\initialState -><br />
> let (oldInt, oldState, oldOutput) = unPackMSIOandRun monad initialState in<br />
> let (newInt, newState, newOutput) = unPackMSIOandRun (doNext oldInt) oldState in<br />
> (newInt, newState, oldOutput ++ newOutput))<br />
<br />
</haskell><br />
<br />
And this is our "return":<br />
<haskell><br />
<br />
> mkMSIO int = Eval_SIO (\s -> (int, s, ""))<br />
<br />
</haskell><br />
<br />
Now we can declare our type, "Eval_SIO", as an instance of the Monad class:<br />
<br />
<haskell><br />
<br />
> instance Monad Eval_SIO where<br />
> return a = mkMSIO a<br />
> (>>=) m f = bindMSIO m f<br />
<br />
</haskell><br />
<br />
Now, the function to increment the counter will also insert an empty<br />
string "" in our monad: "bind" will take care of concatenating it with<br />
the old output:<br />
<br />
<haskell><br />
<br />
> incSIOstate :: Eval_SIO () <br />
> incSIOstate = Eval_SIO (\s -> ((), s + 1, ""))<br />
<br />
</haskell><br />
<br />
The function to insert some new output will just insert a string into<br />
our monad, together with a void Integer (). Since no binding will<br />
occur (>> will be applied), the () will not be taken into<br />
consideration within the anonymous functions automatically created for<br />
us within the do block:<br />
<br />
<haskell><br />
<br />
> print_SIO :: Output -> Eval_SIO ()<br />
> print_SIO x = Eval_SIO (\s -> ((),s, x))<br />
<br />
</haskell><br />
<br />
And now the evaluator, that puts everything together. As you can see<br />
it did not change too much from the previous versions:<br />
<br />
<haskell><br />
<br />
> eval_SIO :: Term -> Eval_SIO Int<br />
> eval_SIO (Con a) = do incSIOstate<br />
> print_SIO (formatLine (Con a) a)<br />
> return a<br />
> eval_SIO (Add t u) = do a <- eval_SIO t<br />
> b <- eval_SIO u<br />
> incSIOstate<br />
> print_SIO (formatLine (Add t u) (a + b))<br />
> return (a + b)<br />
<br />
</haskell><br />
<br />
Running it will require unpacking the monad and feeding it with the initial state 0:<br />
<br />
unPackMSIOandRun (eval_SIO (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12))))) 0<br />
*TheMonadicWay> unPackMSIOandRun (eval_SIO (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12))))) 0<br />
(54,7,"eval (Con 6) <= 6 - eval (Con 16) <= 16 - <br />
eval (Con 20) <= 20 - <br />
eval (Con 12) <= 12 - <br />
eval (Add (Con 20) (Con 12)) <= 32 - <br />
eval (Add (Con 16) (Add (Con 20) (Con 12))) <= 48 - <br />
eval (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <= 54 - ")<br />
*TheMonadicWay> <br />
<br />
(I formatted the output).<br />
<br />
<br />
==If there's a state we need some discipline: Dealing with complexity==<br />
<br />
'''(Text to be done yet: just a summary)'''<br />
<br />
In order to increase the complexity of our monad now we will try to<br />
mix State (counter), Exceptions and Output.<br />
<br />
This is an email [http://www.haskell.org/pipermail/haskell-cafe/2006-August/017672.html I send to the haskell-cafe mailing list]:<br />
<br />
<pre><br />
Now I'm trying to create a statefull evaluator, with output and<br />
exception, but I'm facing a problem I seem not to be able to<br />
conceptually solve.<br />
<br />
Take the code below.<br />
Now, in order to get it run (and try to debug) the Eval_SOI type has a<br />
Raise constructor that produces the same type of SOIE. Suppose instead it<br />
should be constructing something like Raise "something". <br />
Moreover, I wrote a second version of >>=, commented out.<br />
This is just to help me illustrate to problem I'm facing.<br />
<br />
Now, >>= is suppose to return Raise if "m" is matched against Raise<br />
(second version commented out).<br />
If "m" matches SOIE it must return a SOIE only if "f a" does not<br />
returns a Raise (output must be concatenated).<br />
<br />
I seem not to be able to find a way out. Moreover, I cannot understand<br />
if a way out can be possibly found. Something suggests me it could be<br />
related to that Raise "something".<br />
But my feeling is that functional programming could be something out<br />
of the reach of my mind... by the way, I teach Law, so perhaps you'll<br />
forgive me...;-)<br />
<br />
If you can help me to understand this problem all I can promise is<br />
that I'll mention your help in the tutorial I'm trying to write on<br />
"the monadic way"... that seems to lead me nowhere.<br />
<br />
Thanks for your kind attention.<br />
<br />
Andrea<br />
</pre><br />
<br />
This was the code:<br />
<br />
<haskell><br />
data Eval_SOI a = Raise { unPackMSOIandRun :: State -> (a, State, Output) }<br />
| SOIE { unPackMSOIandRun :: State -> (a, State, Output) }<br />
<br />
instance Monad Eval_SOI where<br />
return a = SOIE (\s -> (a, s, ""))<br />
m >>= f = SOIE (\x -><br />
let (a, y, s1) = unPackMSOIandRun m x in<br />
case f a of<br />
SOIE nextRun -> let (b, z, s2) = nextRun y in <br />
(b, z, s1 ++ s2)<br />
Raise e1 -> e1 y --only this happens<br />
<br />
)<br />
-- (>>=) m f = case m of<br />
-- Raise e -> error "ciao" -- why this is not going to happen?<br />
-- SOIE a -> SOIE (\x -><br />
-- let (a, y, s1) = unPackMSOIandRun m x in<br />
-- let (b, z, s2) = unPackMSOIandRun (f a) y in <br />
-- (b, z, s1 ++ s2)) <br />
<br />
<br />
incSOIstate :: Eval_SOI ()<br />
incSOIstate = SOIE (\s -> ((), s + 1, ""))<br />
<br />
print_SOI :: Output -> Eval_SOI ()<br />
print_SOI x = SOIE (\s -> ((),s, x))<br />
<br />
raise x e = Raise (\s -> (x,s,e))<br />
<br />
eval_SOI :: Term -> Eval_SOI Int<br />
eval_SOI (Con a) = do incSOIstate<br />
print_SOI (formatLine (Con a) a)<br />
return a<br />
eval_SOI (Add t u) = do a <- eval_SOI t<br />
b <- eval_SOI u<br />
incSOIstate<br />
print_SOI (formatLine (Add t u) (a + b))<br />
if (a + b) == 42 <br />
then raise (a+b) " = The Ultimate Answer!!"<br />
else return (a + b)<br />
<br />
runEval exp = case eval_SOI exp of<br />
Raise a -> a 0<br />
SOIE p -> let (result, state, output) = p 0 in<br />
(result,state,output)<br />
<br />
<br />
<br />
--runEval (Add (Con 10) (Add (Con 28) (Add (Con 40) (Con 2))))<br />
</haskell><br />
<br />
This code will produce <br />
<br />
eval (Con 10) <= 10 -<br />
eval (Con 28) <= 28 -<br />
eval (Con 40) <= 40 -<br />
eval (Con 2) <= 2 - = The Ultimate Answer!!<br />
eval (Add (Con 28) (Add (Con 40) (Con 2))) <= 70 -<br />
eval (Add (Con 10) (Add (Con 28) (Add (Con 40) (Con 2)))) <= 80 -<br />
<br />
The exception appears in the output, but executioon is not stopped.<br />
<br />
===Monadic evaluator with output, counter and exception, in do-notation===<br />
<br />
Brian Hulley [http://www.haskell.org/pipermail/haskell-cafe/2006-August/017680.html came up with this solution]:<br />
<br />
<haskell><br />
<br />
> -- thanks to Brian Hulley<br />
> data Result a<br />
> = Good a State Output<br />
> | Bad State Output Exception<br />
> deriving Show<br />
<br />
> newtype Eval_SIOE a = SIOE {runSIOE :: State -> Result a}<br />
<br />
> instance Monad Eval_SIOE where<br />
> return a = SIOE (\s -> Good a s "")<br />
> m >>= f = SIOE $ \x -><br />
> case runSIOE m x of<br />
> Good a y o1 -><br />
> case runSIOE (f a) y of<br />
> Good b z o2 -> Good b z (o1 ++ o2)<br />
> Bad z o2 e -> Bad z (o1 ++ o2) e<br />
> Bad z o2 e -> Bad z o2 e<br />
<br />
> raise_SIOE e = SIOE (\s -> Bad s "" e)<br />
<br />
> incSIOEstate :: Eval_SIOE ()<br />
> incSIOEstate = SIOE (\s -> Good () (s + 1) "")<br />
<br />
> print_SIOE :: Output -> Eval_SIOE ()<br />
> print_SIOE x = SIOE (\s -> Good () s x)<br />
<br />
<br />
> eval_SIOE :: Term -> Eval_SIOE Int<br />
> eval_SIOE (Con a) = do incSIOEstate<br />
> print_SIOE (formatLine (Con a) a)<br />
> return a<br />
> eval_SIOE (Add t u) = do a <- eval_SIOE t<br />
> b <- eval_SIOE u<br />
> incSIOEstate<br />
> let out = formatLine (Add t u) (a + b)<br />
> print_SIOE out<br />
> if (a+b) == 42<br />
> then raise_SIOE $ out ++ "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
> runEval exp = case runSIOE (eval_SIOE exp) 0 of<br />
> Bad s o e -> "Error at iteration n. " ++ show s ++ <br />
> " - Output stack = " ++ o ++ <br />
> " - Exception = " ++ e<br />
> Good a s o -> "Result = " ++ show a ++ <br />
> " - Iterations = " ++ show s ++ " - Output = " ++ o<br />
<br />
</haskell><br />
<br />
Run with runEval (Add (Con 18) (Add (Con 12) (Add (Con 10) (Con 2))))<br />
<br />
==Suggested readings==<br />
<br />
:Cale Gibbard, [[Monads as containers]]<br />
:Jeff Newbern, [http://haskell.org/all_about_monads/html/contmonad.html All About Monads]<br />
:[[IO inside]]<br />
:[http://sigfpe.blogspot.com/2006/08/you-could-have-invented-monads-and.html You Could Have Invented Monads! (And Maybe You Already Have.) by sigfpe]<br />
<br />
<br />
==Acknowledgments==<br />
<br />
Thanks to Neil Mitchell, Daniel Fisher, Bulat Ziganzhin, Brian Hulley<br />
and Udo Stenzel for the invaluable help they gave, in the<br />
[http://www.haskell.org/mailman/listinfo/haskell-cafe haskell-cafe mailing list], <br />
in understanding this topic.<br />
<br />
I couldn't do it without their help.<br />
<br />
Obviously errors are totally mine. But this is a wiki so, please,<br />
correct them!<br />
<br />
- [[User:AndreaRossato|Andrea Rossato]]<br />
<br />
[[Category:Tutorials]]<br />
[[Category:Monad]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=The_Monadic_Way&diff=14661The Monadic Way2007-07-24T22:35:51Z<p>BrettGiles: Links</p>
<hr />
<div>'''Note''' Since the size of the previous file was getting too big for a wiki, the tutorial has been divided into two parts: [[The Monadic Way Part I]] and [[The Monadic Way Part II]]. See below for some introductory remarks.<br />
<br />
'''Contents'''<br />
<br />
;[[Meet Bob The Monadic Lover]]<br />
:A (supposed-to-be) funny and short introduction to Monads, with code but without any reference to category theory: what monads look like and what they are useful for, from the perspective of a ... lover. It could be an introduction to "The Monadic Way" tutorial.<br />
<br />
;[[The Monadic Way/Part I]]<br />
:In the first part of the tutorial we will start from a very simple evaluator that will be transformed into a monadic evaluator with an increasing number of features: output, exceptions, and state: a very simple counter for tracking the number of recursions of the evaluation precess.<br />
<br />
;[[The Monadic Way/Part II]]<br />
:In the second part of the tutorial we will see how to take complexity out of our monadic evaluator with the use of monadic transformers, and specifically StateT. This part is just a skeleton, since, for the time being, it contains only the code.<br />
<br />
<br />
==Preliminary remarks==<br />
<br />
When I started writing this tutorial I though that the only way to<br />
explain monads to a newcomer was to show them from the inside, with<br />
the use of lambda abstraction. Not only because this is the way Philip<br />
Wedler's<br />
[http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf paper] <br />
adopts, but also because I believed, and still believe, that the<br />
only way to understand what bind (>>=) does is to explain it as a<br />
function that takes a monad and an anonymous function.<br />
<br />
I had this feeling because I am a newcomer, and this is the way I came to understand monads.<br />
<br />
I did not received very much feedback for this tutorial, and I must<br />
admit that I would like to. But one person, on the haskell-cafe<br />
mailing list, [http://www.haskell.org/pipermail/haskell-cafe/2006-September/017740.html told me]<br />
that:<br />
<pre><br />
imho your tutorial makes the error that is a very typical: when you<br />
write your tutorial you already know what are monads and what the<br />
program you will construct at the end. but your reader don't know all these!<br />
for such fresh reader this looks as you made some strange steps, write<br />
some ugly code and he doesn't have chances to understand that this ugly<br />
code is written just to show that this can be simplified by using monads.<br />
</pre><br />
<br />
I believe that Bulat is right. In this tutorial you go through some<br />
code that is '''really''' ugly and then, with some kind of magic, it<br />
turns out in the (redundant but) clean evaluator of the end of [[The Monadic Way/Part II]].<br />
<br />
I took that mail as a challenge and <br />
[http://www.haskell.org/pipermail/haskell-cafe/2006-September/017778.html I responded] <br />
by writing [[Meet Bob The Monadic Lover]].<br />
<br />
In "Meet Bob" the code is clean, variable names are very descriptive,<br />
and you see that I can create a monad without any use of lambda<br />
abstraction.<br />
<br />
Bind (in "Meet Bob" is askLover) now takes a monad and a partial<br />
application, not an anonymous function.<br />
<br />
Obviously you can see an anonymous function as a partial application.<br />
<br />
The problem, I think, is that, in "Meet Bob", you cannot understand<br />
the strict relation between what I did before and what I do when I<br />
start using the "do-notation". You see that the same functions are<br />
being used ("tellMyself" and "newLove"), but "andrea <- tellMyself 1"<br />
is not explained. It's just magic.<br />
<br />
The fact is that you cannot understand "andrea <- tellMyself 1"<br />
without the use of lambda abstraction.<br />
<br />
I should have written an intermediate step, something like this:<br />
<haskell><br />
drunk = do newLove "Paula " >><br />
(tellLover 1 10) >>= \paula -><br />
(tellMyself 3) >>= \lorena -> tellMyself (paula + lorena)<br />
<br />
</haskell><br />
<br />
With this approach I think you can understand '''why and how''' you<br />
come to write something like this:<br />
<haskell><br />
drunk = do newLove "Paula "<br />
paula <- (tellLover 1 10)<br />
lorena <- tellMyself 3<br />
tellMyself (paula + lorena)<br />
</haskell><br />
<br />
That is to say, in this way you can see a do block as a series of<br />
nested anonymous functions whose arguments are bound to some value by<br />
the application of >>=. Anonymous functions that bind to some value<br />
the variables appearing after the "->" ("paula" and "lorena").<br />
<br />
To summarize, I think that even if you can start using monads without<br />
understanding that what happens inside a "do" block is strictly<br />
related with lambda calculus, I don't think you can claim you<br />
understand monads just because you are using them. <br />
<br />
And I'm quite sure that if a problem arises somewhere you can have a<br />
very difficult time in trying to find out what the problem is. This is<br />
even more true when you start doing monadic transformations.<br />
<br />
==How to explain monads to newcomers?==<br />
<br />
Monads are not an impossible-to-understand-unless-you-have-a-phd<br />
topic. I don't know if I can claim I'm a living proof of this<br />
assumption, since I have a PhD. But please take into account that I<br />
have a PhD in Comparative Private Law! Nothing related to computer<br />
science. And I claim I understand monads.<br />
<br />
Moreover, since I have come to understand them, I think I can try to<br />
explain them to newcomers like me. This is why I started writing this<br />
tutorial.<br />
<br />
Still, in order to understand them I studied, and I studied hard. I<br />
wanted to understand, it was difficult, and I kept studying. Going<br />
back to the foundation when needed.<br />
<br />
So, I cannot explain monads to you unless you are willing to study. I can<br />
show you the way, but you must take your time and follow that way.<br />
<br />
==What do I need to know to understand monads?==<br />
<br />
===Functional programming===<br />
<br />
First you need at least a basic understanding of functional<br />
programming. <br />
<br />
This is going to be the easiest step, because there is an invaluable<br />
resource available on line for free.<br />
<br />
This is what I did: I spent 20 hours of my life watching the Video<br />
Lectures by Hal Abelson and Gerald Jay Sussman on<br />
[http://swiss.csail.mit.edu/classes/6.001/abelson-sussman-lectures/ Structure and Interpretation of Computer Programs].<br />
<br />
This course, and the annexed text book (I did not read it entirely),<br />
are an amazing introduction to computer science: you start by learning<br />
some basic Scheme and then Abelson and Sussman will bring you, step by<br />
step, to understand evaluation, interpretation and compilation of Lisp<br />
(Scheme) code.<br />
<br />
The course is clear, interesting, funny and will provide you with a<br />
basic, but strong, understanding of functional programming.<br />
<br />
Believe me: if you like programming but don't have a computer science<br />
curriculum, you'll find out that spending 20 hours of your life to<br />
watch that course has been the most productive investment of your<br />
learning life.<br />
<br />
===My problem with Haskell===<br />
<br />
I find Haskell an amazingly expressive programming language. It makes<br />
it incredibly easy to perform very difficult tasks, just like monads,<br />
for instance.<br />
<br />
The problem is that, in doing so, it makes it difficult to understand<br />
Haskell to newcomers.<br />
<br />
I must confess that tutorials and other learning material are quite<br />
dissatisfying on this regards too.<br />
<br />
Since Haskell seems to make easy what is not easy, these tutorial take<br />
the "it's easy" approach.<br />
<br />
I will give you an example. I think that the<br />
[http://www.cs.utah.edu/~hal/htut/ "Yet Another Haskell Tutorial"] is<br />
a really good attempt to explain Haskell, and if you want to<br />
understand this tutorial you need to read it at least for getting a<br />
good understanding of the Haskell type system. <br />
<br />
The tutorial explains monads and explains the "do notation" in terms<br />
of lambda abstraction (par. 9.1, p. 120). Still, to the lambda<br />
operator ("\") the tutorial dedicates only 17 lines in par. 4.4.1.<br />
Moreover "\" is explained just as another way of creating functions.<br />
<br />
This probably makes sense for a functional programmer who is studying<br />
Haskell for the first time. But, on the other side it will make the<br />
newcomer, who's not a functional programmer, believe that explaining<br />
monads in terms of "\" is just ugly, and definitely not Haskell.<br />
<br />
This is my problem with Haskell: it hides complexity with<br />
constructions like "let...in", "where", "do".<br />
<br />
Still I believe that if you want to use those constructions you must<br />
know what they do. And they do ugly stuff like the one you'll be<br />
looking at in this tutorial.<br />
<br />
I am not saying that this is ''the'' way to learn Haskell. I'm just<br />
saying that this is the way I'm learning Haskell. And this is the way<br />
this tutorial has been written.<br />
<br />
===Starting from the inside or the outside?===<br />
<br />
In This tutorial I show monads from their inside. In "Meet Bob" I do<br />
the opposite. As I said I think (and I did it on purpose) that after<br />
reading "Meet Bob" you can have a general idea of what a monad is, but<br />
you need to go inside a monad to see how it works.<br />
<br />
As a suggestion, I'd invite you to start with "Meet Bob", and then<br />
procede with the tutorial.<br />
<br />
I hope the these two approaches will give you an overall image of a<br />
monad.<br />
<br />
===Prerequisites===<br />
<br />
As I said, in order to understand this tutorial you need:<br />
* a basic understanding of functional programming (this is required to understand Haskell after all)<br />
* a basic understanding of the type system:<br />
** how to create new types (with "data" and "newtype")<br />
** how to use type constructors to construct and to match types and their internal components<br />
** how to use a label field to retrieve a type internal component<br />
* a basic understanding of lambda abstraction<br />
<br />
I hope I'll be able to write a short introductory summary to these<br />
topics (I will put it below this introductory remarks).<br />
<br />
Have fun with Haskell!<br />
<br />
- [[User:AndreaRossato|Andrea Rossato]]<br />
<br />
[[Category:Tutorials]]<br />
[[Category:Idioms]]<br />
[[Category:Monad]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=The_Monadic_Way/Part_II&diff=14660The Monadic Way/Part II2007-07-24T22:34:07Z<p>BrettGiles: Remove superfluous comment at top now that this is a sub page.</p>
<hr />
<div><br />
''Note: this is just the skeleton of this part, with code but very little text''<br />
<br />
==Summary of the previous part==<br />
<br />
<div id="BasicEval"><br />
<haskell><br />
<br />
> module TheMonadicWay where<br />
> data Term = Con Int<br />
> | Add Term Term<br />
> deriving (Show)<br />
<br />
> type Exception = String<br />
> type O = String<br />
> type Output = String<br />
<br />
> formatLine :: Term -> Int -> Output<br />
> formatLine t a = "eval (" ++ show t ++ ") <= " ++ show a ++ " - " <br />
<br />
<br />
</haskell><br />
<br />
<br />
==Taking complexity out of a monad: Monadic transformers==<br />
<br />
We have seen how the complexity of (>>=) was growing by adding<br />
operations to be done.<br />
<br />
We will do the opposite: we will implement a state transformer (I<br />
copied StateT).<br />
<br />
We will embed our monad in the StateT monad and we will start moving<br />
state and output from the inner monad (our one) to the outer monad<br />
(StateT).<br />
<br />
===The StateT monad: A monad container=== <br />
Let me introduce StateT with some useful functions:<br />
<br />
<haskell><br />
<br />
> newtype StateT s m a = StateT {runStateT :: s -> m (a,s) } --StateT (s -> m (a,s))<br />
<br />
> instance Monad m => Monad (StateT s m) where<br />
> return a = StateT (\s -> return (a,s))<br />
> StateT m1 >>= k = StateT (\s -> do ~(a,s1) <- m1 s<br />
> let StateT m2 = k a<br />
> m2 s1)<br />
<br />
> -- | Execute a stateful computation, as a result we get<br />
> -- the result of the computation, and the final state.<br />
> runState :: s -> StateT s m a -> m (a,s)<br />
> runState s (StateT m) = m s<br />
<br />
> -- | Execute a stateful computation, ignoring the final state.<br />
> evalState :: Functor m => s -> StateT s m a -> m a<br />
> evalState s m = fmap fst (runState s m)<br />
<br />
> -- | Execute a stateful computation, just for the side effect.<br />
> execState :: Functor m => s -> StateT s m a -> m s<br />
> execState s m = fmap snd (runState s m)<br />
<br />
<br />
> lift :: (Monad m) => m a -> StateT s m a<br />
> lift m = StateT (\s -> do x <- m<br />
> return (x,s))<br />
<br />
</haskell><br />
<br />
StateT is pleased to meet you!.<br />
<br />
===StateT as a counter, and monadic evaluator with output and exceptions===<br />
And now out monad, with state out from it:<br />
<br />
<haskell><br />
<br />
> data MTa a = FailTa Exception<br />
> | DoneTa {unpackDoneTa :: (a,O) }<br />
> deriving (Show)<br />
<br />
<br />
> instance Monad MTa where<br />
> return a = DoneTa (a, "")<br />
> m >>= f = case m of<br />
> FailTa e -> FailTa e<br />
> DoneTa (a, x) -> case (f a) of<br />
> FailTa e1 -> FailTa e1 <br />
> DoneTa (b, y) -> DoneTa (b, x ++ y) <br />
<br />
> instance Functor MTa where<br />
> fmap _ (FailTa e) = FailTa e<br />
> fmap f (DoneTa (r,o)) = DoneTa ((f r),o)<br />
<br />
> raiseTa_SIOE :: O -> StateT Int MTa a<br />
> raiseTa_SIOE e = lift (FailTa e)<br />
<br />
> printTa_SIOE :: O -> StateT Int MTa ()<br />
> printTa_SIOE x = lift (DoneTa ((), x))<br />
<br />
> incTaState :: StateT Int MTa ()<br />
> incTaState = StateT (\s -> return ((), s + 1))<br />
<br />
> evalTa_SIOE :: Term -> StateT Int MTa Int<br />
> evalTa_SIOE (Con a) = do incTaState<br />
> printTa_SIOE (formatLine (Con a) a)<br />
> return a<br />
> evalTa_SIOE (Add t u) = do a <- evalTa_SIOE t<br />
> b <- evalTa_SIOE u<br />
> incTaState<br />
> let out = formatLine (Add t u) (a + b)<br />
> printTa_SIOE out<br />
> if (a+b) == 42<br />
> then raiseTa_SIOE $ <br />
> out ++ "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
> runEvalTa :: Term -> String<br />
> runEvalTa exp = case runStateT (evalTa_SIOE exp) 0 of <br />
> FailTa e -> e<br />
> DoneTa (~(r,s),o)-> "Result = " ++ show r ++ <br />
> "; Iteration = " ++ show s ++ <br />
> "; Output = " ++ o<br />
<br />
> runEvalTa1 :: Term -> String<br />
> runEvalTa1 exp = case runState 0 (evalTa_SIOE exp) of <br />
> FailTa e -> e<br />
> DoneTa ((r,s),o) -> "Result = " ++ show r ++ <br />
> "; Iteration = " ++ show s ++ <br />
> "; Output = " ++ o<br />
<br />
> runEvalTa2 :: Term -> String<br />
> runEvalTa2 exp = case evalState 0 (evalTa_SIOE exp) of <br />
> FailTa e -> e<br />
> DoneTa (r,o) -> "Result = " ++ show r ++ "; Output = " ++ o<br />
<br />
> runEvalTa3 :: Term -> String<br />
> runEvalTa3 exp = case execState 0 (evalTa_SIOE exp) of <br />
> FailTa e -> e<br />
> DoneTa (s,o) -> "Iterations = " ++ show s ++ "; Output = " ++ o <br />
<br />
</haskell><br />
<br />
===StateT to keep output and counter, and monadic evaluator with (only) exceptions===<br />
<br />
Now we take output away from the inner monad and place it in the outer<br />
one (StateT):<br />
<br />
<haskell><br />
<br />
<br />
> data MTb a = FailTb Exception<br />
> | DoneTb {unpackDoneTb :: a }<br />
> deriving (Show)<br />
<br />
> type StateIO = (O,Int)<br />
<br />
> instance Monad MTb where<br />
> return a = DoneTb a<br />
> m >>= f = case m of<br />
> FailTb e -> FailTb e<br />
> DoneTb a -> f a<br />
<br />
> instance Functor MTb where<br />
> fmap _ (FailTb e) = FailTb e<br />
> fmap f (DoneTb b) = DoneTb (f b)<br />
<br />
<br />
> raiseTb_SIOE :: O -> StateT StateIO MTb a<br />
> raiseTb_SIOE e = lift (FailTb e)<br />
<br />
> printTb_SIOE :: O -> StateT StateIO MTb ()<br />
> printTb_SIOE x = StateT (\(o,s) -> return ((), (o ++ x,s)))<br />
<br />
> incTbStateIO :: StateT StateIO MTb ()<br />
> incTbStateIO = StateT (\(o,s) -> return ((), (o,s + 1)))<br />
<br />
> evalTb_SIOE :: Term -> StateT StateIO MTb Int<br />
> evalTb_SIOE (Con a) = do incTbStateIO<br />
> printTb_SIOE (formatLine (Con a) a)<br />
> return a<br />
> evalTb_SIOE (Add t u) = do a <- evalTb_SIOE t<br />
> b <- evalTb_SIOE u<br />
> incTbStateIO<br />
> let out = formatLine (Add t u) (a + b)<br />
> printTb_SIOE out<br />
> if (a+b) == 42<br />
> then raiseTb_SIOE $ <br />
> out ++ "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
</haskell><br />
<br />
We take away complexity from >>= and put it in the function we need<br />
to use to manipulate content in our StateT monad.<br />
<br />
These are some wrapper to the evaluator to get the result and the<br />
side-effects produced by evaluation:<br />
<br />
<haskell><br />
<br />
> runEvalTb :: Term -> String<br />
> runEvalTb exp = case runStateT (evalTb_SIOE exp) ("",0) of<br />
> FailTb e -> e<br />
> DoneTb (r,~(o,s)) -> "Result = " ++ show r ++ <br />
> "; Iteration = " ++ show s ++ <br />
> "; Output = " ++ o<br />
<br />
<br />
> runEvalTb1 :: Term -> String<br />
> runEvalTb1 exp = case runState ("",0) (evalTb_SIOE exp) of <br />
> FailTb e -> e<br />
> DoneTb (r,~(o,s)) -> "Result = " ++ show r ++ <br />
> "; Iteration = " ++ show s ++ <br />
> "; Output = " ++ o<br />
<br />
> runEvalTb2 :: Term -> String<br />
> runEvalTb2 exp = case evalState ("",0) (evalTb_SIOE exp) of <br />
> FailTb e -> e<br />
> DoneTb r -> "Result = " ++ show r<br />
<br />
> runEvalTb3 :: Term -> String<br />
> runEvalTb3 exp = case execState ("",0) (evalTb_SIOE exp) of <br />
> FailTb e -> e<br />
> DoneTb (o,s) -> "Iterations = " ++ show s ++ <br />
> " - Output = " ++ o<br />
<br />
</haskell><br />
<br />
===StateT to keep output, counter and debug. The monadic evaluator is only for failable computations===<br />
<br />
And now we will keep in the inner monad only the result of the evaluation.<br />
<br />
<haskell><br />
<br />
> data MT a = FailT Exc<br />
> | DoneT {unpackDoneT :: a }<br />
> deriving (Show)<br />
<br />
> type Exc = String<br />
> type IOstack = [Output]<br />
> newtype StateTIO = StateTIO {unPackStateTIO :: (IOstack,Exc,Int)}<br />
> deriving(Show)<br />
<br />
> instance Monad MT where<br />
> return a = DoneT a<br />
> m >>= f = case m of<br />
> FailT e -> FailT e<br />
> DoneT a -> f a<br />
<br />
> instance Functor MT where<br />
> fmap _ (FailT a) = FailT a<br />
> fmap f (DoneT a) = DoneT (f a)<br />
<br />
</haskell><br />
<br />
Simple isn't it?<br />
<br />
The complexity is now below:<br />
<br />
<haskell><br />
<br />
> stopExecT_SIOE :: Output -> StateT StateTIO MT Int<br />
> stopExecT_SIOE exc = StateT (\s -> do x <- FailT exc<br />
> return (x, s))<br />
<br />
> catchT_SIOE exc = StateT (\(StateTIO (o,e,s)) -> <br />
> return ((), StateTIO (o ,"Exception at Iteration " ++<br />
> show s ++ ": " ++ exc ++ " - " ++ e,s)))<br />
<br />
> printT_SIOE :: Output -> StateT StateTIO MT ()<br />
> printT_SIOE x = StateT (\(StateTIO (o,e,s)) -> return ((), StateTIO (x:o,e,s)))<br />
<br />
> incTstateIO :: StateT StateTIO MT ()<br />
> incTstateIO = StateT (\(StateTIO (o,e,s)) -> return ((),StateTIO (o,e,s + 1)))<br />
<br />
> evalT_SIOE :: Term -> StateT StateTIO MT Int<br />
> evalT_SIOE (Con a) = do incTstateIO<br />
> printT_SIOE (formatLine (Con a) a)<br />
> return a<br />
> evalT_SIOE (Add t u) = do a <- evalT_SIOE t<br />
> b <- evalT_SIOE u<br />
> incTstateIO<br />
> let out = formatLine (Add t u) (a + b)<br />
> printT_SIOE out<br />
> case (a+b) of <br />
> 42 -> do catchT_SIOE "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> return (a+b)<br />
> 11 -> stopExecT_SIOE "11.... I do not like this number!"<br />
> otherwise -> return (a + b)<br />
<br />
</haskell><br />
<br />
But now we have exceptions to stop execution and debugging output.<br />
<br />
Some helper functions:<br />
<br />
<haskell><br />
<br />
> runEvalT :: Term -> String<br />
> runEvalT exp = case runStateT (evalT_SIOE exp) (StateTIO ([],"",0)) of<br />
> FailT e -> e<br />
> DoneT (r,StateTIO (o,e,s)) -> "Result = " ++ show r ++ "; Iteration = " ++ show s ++ <br />
> "; Output = " ++ show o ++ " - Exceptions = " ++ e<br />
<br />
<br />
> runEvalT1 :: Term -> String<br />
> runEvalT1 exp = case runState (StateTIO ([],"",0)) (evalT_SIOE exp) of <br />
> FailT e -> e<br />
> DoneT (r,StateTIO(o,e,s)) -> "Result = " ++ show r ++ "; Iteration = " ++ show s <br />
> ++ "; Output = " ++ show o ++ " - Exceptions = " ++ e<br />
<br />
> runEvalT2 :: Term -> String<br />
> runEvalT2 exp = case evalState (StateTIO ([],"",0)) (evalT_SIOE exp) of <br />
> FailT e -> e<br />
> DoneT r -> "Result = " ++ show r<br />
<br />
> runEvalT3 :: Term -> String<br />
> runEvalT3 exp = case execState (StateTIO ([],"",0)) (evalT_SIOE exp) of <br />
> FailT e -> e<br />
> DoneT (StateTIO (o,e,s)) -> "Iterations = " ++ show s ++ <br />
<br />
> " - Output = " ++ show o ++ " - Exceptions = " ++ e<br />
> showOut :: [String] -> IO ()<br />
> showOut [] = return ()<br />
> showOut (a:xs) = do print a<br />
> showOut xs<br />
<br />
> runMyEval :: Term -> IO ()<br />
> runMyEval exp = let StateTIO (a,b,c) = unpackDoneT $ execState (StateTIO ([],"",0)) (evalT_SIOE exp) in<br />
> showOut $ reverse a<br />
<br />
</haskell><br />
<br />
Some tests:<br />
<pre><br />
*TheMonadicWay> runEvalT (Add (Con 18) (Add (Con 12) (Add (Con 10) (Con 2))))<br />
"Result = 42; Iteration = 7; Output = [\"eval (Add (Con 18) (Add (Con 12) (Add (Con 10) (Con 2)))) <= 42 - \",<br />
\"eval (Add (Con 12) (Add (Con 10) (Con 2))) <= 24 - \",<br />
\"eval (Add (Con 10) (Con 2)) <= 12 - \",<br />
\"eval (Con 2) <= 2 - \",<br />
\"eval (Con 10) <= 10 - \",<br />
\"eval (Con 12) <= 12 - \",<br />
\"eval (Con 18) <= 18 - \"] - <br />
Exceptions = Exception at Iteration 7: The Ultimate Answer Has Been Computed!! Now I'm tired! - "<br />
*TheMonadicWay> runEvalT2 (Add (Con 18) (Add (Con 12) (Add (Con 10) (Con 2))))<br />
"Result = 42"<br />
*TheMonadicWay> runEvalT3 (Add (Con 18) (Add (Con 12) (Add (Con 10) (Con 2))))<br />
"Iterations = 7 - Output = [\"eval (Add (Con 18) (Add (Con 12) (Add (Con 10) (Con 2)))) <= 42 - \",<br />
\"eval (Add (Con 12) (Add (Con 10) (Con 2))) <= 24 - \",<br />
\"eval (Add (Con 10) (Con 2)) <= 12 - \",<br />
\"eval (Con 2) <= 2 - \",<br />
\"eval (Con 10) <= 10 - \",<br />
\"eval (Con 12) <= 12 - \",<br />
\"eval (Con 18) <= 18 - \"] - <br />
Exceptions = Exception at Iteration 7: The Ultimate Answer Has Been Computed!! Now I'm tired! - "<br />
*TheMonadicWay> runEvalT3 (Add (Con 1) (Add (Con 7) (Add (Con 1) (Con 2))))<br />
"Iterations = 7 - Output = [\"eval (Add (Con 1) (Add (Con 5) (Add (Con 1) (Con 2)))) <= 9 - \",<br />
\"eval (Add (Con 5) (Add (Con 1) (Con 2))) <= 8 - \",<br />
\"eval (Add (Con 1) (Con 2)) <= 3 - \",<br />
\"eval (Con 2) <= 2 - \",<br />
\"eval (Con 1) <= 1 - \",<br />
\"eval (Con 5) <= 5 - \",<br />
\"eval (Con 1) <= 1 - \"] - Exceptions = "<br />
*TheMonadicWay> runEvalT3 (Add (Con 1) (Add (Con 7) (Add (Con 1) (Con 2))))<br />
"11.... I do not like this number!"<br />
*TheMonadicWay> runMyEval (Add (Add (Add (Add (Con 10) (Con 2)) (Add (Con 12) (Con 3))) (Con 3)) (Con 10))<br />
"eval (Con 10) <= 10 - "<br />
"eval (Con 2) <= 2 - "<br />
"eval (Add (Con 10) (Con 2)) <= 12 - "<br />
"eval (Con 12) <= 12 - "<br />
"eval (Con 3) <= 3 - "<br />
"eval (Add (Con 12) (Con 3)) <= 15 - "<br />
"eval (Add (Add (Con 10) (Con 2)) (Add (Con 12) (Con 3))) <= 27 - "<br />
"eval (Con 3) <= 3 - "<br />
"eval (Add (Add (Add (Con 10) (Con 2)) (Add (Con 12) (Con 3))) (Con 3)) <= 30 - "<br />
"eval (Con 10) <= 10 - "<br />
"eval (Add (Add (Add (Add (Con 10) (Con 2)) (Add (Con 12) (Con 3))) (Con 3)) (Con 10)) <= 40 - "<br />
*TheMonadicWay><br />
</pre><br />
<br />
<br />
==The final cut==<br />
<br />
===StateT for output, counter, debug, using the standard library===<br />
<br />
<haskell><br />
module MyStateT where<br />
import Control.Monad.State hiding (State)<br />
<br />
data Term = Con Int<br />
| Add Term Term<br />
deriving (Show)<br />
<br />
type IOStack = [Output]<br />
type Output = String<br />
type Debug = [String]<br />
data EvalST = State {getIOS :: IOStack, getDebug :: Debug, getCount:: Int}<br />
deriving(Show)<br />
<br />
<br />
type Exception = String<br />
data MT a = Fail Exception<br />
| Done {unpackDone :: a }<br />
deriving (Show)<br />
<br />
type Eval s a = StateT s MT a<br />
<br />
instance Monad MT where<br />
return a = Done a<br />
m >>= f = case m of<br />
Fail e -> Fail e<br />
Done a -> f a<br />
<br />
instance Functor MT where<br />
fmap _ (Fail a) = Fail a<br />
fmap f (Done a) = Done (f a)<br />
<br />
emptyState = State [] [] 0<br />
<br />
stopExecT exc = lift $ Fail exc<br />
<br />
catchT e = do st <- get<br />
let s = getCount st<br />
let es = getDebug st<br />
let o = getIOS st<br />
let exc = "Debug msg at Iteration " ++ show s ++ ": " ++ e<br />
put $ State o (exc:es) s<br />
<br />
printT :: Output -> Eval EvalST ()<br />
printT o = do st <- get<br />
let s = getCount st<br />
let e = getDebug st<br />
let os = getIOS st<br />
let out = show s ++ " - " ++ o<br />
put $ State (out:os) e s<br />
<br />
incTcounter :: Eval EvalST ()<br />
incTcounter = do st <- get<br />
let s = getCount st<br />
let e = getDebug st<br />
let o = getIOS st<br />
put $ State o e (s+1)<br />
<br />
evalT :: Term -> Eval EvalST Int<br />
evalT (Con a) = do incTcounter<br />
printT (formatLine (Con a) a)<br />
return a<br />
evalT (Add t u) = do a <- evalT t<br />
b <- evalT u<br />
incTcounter<br />
let out = formatLine (Add t u) (a + b)<br />
printT out<br />
case (a+b) of <br />
42 -> do catchT "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
return (a+b)<br />
11 -> stopExecT "11.... I do not like this number!"<br />
otherwise -> return (a + b)<br />
<br />
<br />
formatLine :: Term -> Int -> Output<br />
formatLine t a = "eval (" ++ show t ++ ") <= " ++ show a <br />
<br />
printAll :: [String] -> IO ()<br />
printAll [] = return ()<br />
printAll (a:xs) = do putStrLn a<br />
printAll xs<br />
<br />
eval :: Term -> IO ()<br />
eval exp = case execStateT (evalT exp) emptyState of<br />
Fail e -> putStrLn e<br />
Done (State a b c )<br />
-> do printAll $ reverse a<br />
putStrLn $ show $ unpackDone $ <br />
evalStateT (evalT exp) emptyState<br />
case b of<br />
[] -> putStrLn $ "Iterations: " ++ show c<br />
_ -> do printAll $ reverse b<br />
putStrLn $ "Iterations: " ++ show c<br />
<br />
---- testing functions ----<br />
runEvalT :: Term -> String<br />
runEvalT exp = case runStateT (evalT exp) emptyState of<br />
Fail e -> e<br />
Done (r,State o e s) -> "Result = " ++ show r ++ <br />
"; Iteration = " ++ show s ++ <br />
"; Output = " ++ show o ++<br />
" - Exceptions = " ++ show e<br />
<br />
getEvalResult :: Term -> String<br />
getEvalResult exp = case evalStateT (evalT exp) emptyState of <br />
Fail e -> e<br />
Done r -> "Result = " ++ show r<br />
<br />
<br />
getSideEffects :: Term -> String<br />
getSideEffects exp = case execStateT (evalT exp) emptyState of <br />
Fail e -> e<br />
Done (State o e s) -> "Iterations = " ++ show s ++ <br />
" - Output = " ++ show o ++ <br />
" - Exceptions = " ++ show e<br />
<br />
{-<br />
Some runs:<br />
<br />
*MyStateT> eval (Add (Add (Add (Add (Con 40) (Con 2)) (Add (Con 12) (Con 30))) (Con 3)) (Con 10))<br />
1 - eval (Con 40) <= 40<br />
2 - eval (Con 2) <= 2<br />
3 - eval (Add (Con 40) (Con 2)) <= 42<br />
4 - eval (Con 12) <= 12<br />
5 - eval (Con 30) <= 30<br />
6 - eval (Add (Con 12) (Con 30)) <= 42<br />
7 - eval (Add (Add (Con 40) (Con 2)) (Add (Con 12) (Con 30))) <= 84<br />
8 - eval (Con 3) <= 3<br />
9 - eval (Add (Add (Add (Con 40) (Con 2)) (Add (Con 12) (Con 30))) (Con 3)) <= 87<br />
10 - eval (Con 10) <= 10<br />
11 - eval (Add (Add (Add (Add (Con 40) (Con 2)) (Add (Con 12) (Con 30))) (Con 3)) (Con 10)) <= 97<br />
97<br />
Debug msg at Iteration 3: The Ultimate Answer Has Been Computed!! Now I'm tired!<br />
Debug msg at Iteration 6: The Ultimate Answer Has Been Computed!! Now I'm tired!<br />
Iterations: 11<br />
*MyStateT> <br />
<br />
*MyStateT> eval (Add (Add (Add (Add (Con 10) (Con 2)) (Add (Con 12) (Con 3))) (Add (Con 5) (Con 2))) (Con 2))<br />
1 - eval (Con 10) <= 10<br />
2 - eval (Con 2) <= 2<br />
3 - eval (Add (Con 10) (Con 2)) <= 12<br />
4 - eval (Con 12) <= 12<br />
5 - eval (Con 3) <= 3<br />
6 - eval (Add (Con 12) (Con 3)) <= 15<br />
7 - eval (Add (Add (Con 10) (Con 2)) (Add (Con 12) (Con 3))) <= 27<br />
8 - eval (Con 5) <= 5<br />
9 - eval (Con 2) <= 2<br />
10 - eval (Add (Con 5) (Con 2)) <= 7<br />
11 - eval (Add (Add (Add (Con 10) (Con 2)) (Add (Con 12) (Con 3))) (Add (Con 5) (Con 2))) <= 34<br />
12 - eval (Con 2) <= 2<br />
13 - eval (Add (Add (Add (Add (Con 10) (Con 2)) (Add (Con 12) (Con 3))) (Add (Con 5) (Con 2))) (Con 2)) <= 36<br />
36<br />
Iterations: 13<br />
*MyStateT> <br />
<br />
*MyStateT> eval (Add (Con 5) (Con 6))<br />
11.... I do not like this number!<br />
*MyStateT> <br />
-}<br />
</haskell><br />
<br />
== Next?==<br />
We need a parser to get a string from input and turn into something of type Term!<br />
<br />
Let's see if we'll time for it... Fist we must complete the text above!!<br />
<br />
==Suggested readings==<br />
<br />
Cale Gibbard, [http://haskell.org/haskellwiki/Monads_as_Containers Monads as Containers]<br />
<br />
Jeff Newbern, [http://haskell.org/all_about_monads/html/contmonad.html All About Monads]<br />
<br />
[http://haskell.org/haskellwiki/IO_inside IO Inside]<br />
<br />
[http://sigfpe.blogspot.com/2006/08/you-could-have-invented-monads-and.html You Could Have Invented Monads! (And Maybe You Already Have.) by sigfpe]<br />
<br />
<br />
==Acknowledgments==<br />
<br />
Thanks to Neil Mitchell, Daniel Fisher, Bulat Ziganzhin, Brian Hulley<br />
and Udo Stenzel for the invaluable help they gave, in the<br />
[http://www.haskell.org/mailman/listinfo/haskell-cafe haskell-cafe mailing list], <br />
in understanding this topic.<br />
<br />
I couldn't do it without their help.<br />
<br />
Obviously errors are totally mine. But this is a wiki so, please,<br />
correct them!<br />
<br />
- [[User:AndreaRossato|Andrea Rossato]]<br />
<br />
[[Category:Tutorials]]<br />
[[Category:Monad]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=The_Monadic_Way/Part_II&diff=14658The Monadic Way/Part II2007-07-24T22:33:21Z<p>BrettGiles: The Monadic Way Part II moved to The Monadic Way/Part II</p>
<hr />
<div>'''Note: this is the second part of [[The Monadic Way]]'''<br />
<br />
''Note: this is just the skeleton of this part, with code but very little text''<br />
<br />
==Summary of the previous part==<br />
<br />
<div id="BasicEval"><br />
<haskell><br />
<br />
> module TheMonadicWay where<br />
> data Term = Con Int<br />
> | Add Term Term<br />
> deriving (Show)<br />
<br />
> type Exception = String<br />
> type O = String<br />
> type Output = String<br />
<br />
> formatLine :: Term -> Int -> Output<br />
> formatLine t a = "eval (" ++ show t ++ ") <= " ++ show a ++ " - " <br />
<br />
<br />
</haskell><br />
<br />
<br />
==Taking complexity out of a monad: Monadic transformers==<br />
<br />
We have seen how the complexity of (>>=) was growing by adding<br />
operations to be done.<br />
<br />
We will do the opposite: we will implement a state transformer (I<br />
copied StateT).<br />
<br />
We will embed our monad in the StateT monad and we will start moving<br />
state and output from the inner monad (our one) to the outer monad<br />
(StateT).<br />
<br />
===The StateT monad: A monad container=== <br />
Let me introduce StateT with some useful functions:<br />
<br />
<haskell><br />
<br />
> newtype StateT s m a = StateT {runStateT :: s -> m (a,s) } --StateT (s -> m (a,s))<br />
<br />
> instance Monad m => Monad (StateT s m) where<br />
> return a = StateT (\s -> return (a,s))<br />
> StateT m1 >>= k = StateT (\s -> do ~(a,s1) <- m1 s<br />
> let StateT m2 = k a<br />
> m2 s1)<br />
<br />
> -- | Execute a stateful computation, as a result we get<br />
> -- the result of the computation, and the final state.<br />
> runState :: s -> StateT s m a -> m (a,s)<br />
> runState s (StateT m) = m s<br />
<br />
> -- | Execute a stateful computation, ignoring the final state.<br />
> evalState :: Functor m => s -> StateT s m a -> m a<br />
> evalState s m = fmap fst (runState s m)<br />
<br />
> -- | Execute a stateful computation, just for the side effect.<br />
> execState :: Functor m => s -> StateT s m a -> m s<br />
> execState s m = fmap snd (runState s m)<br />
<br />
<br />
> lift :: (Monad m) => m a -> StateT s m a<br />
> lift m = StateT (\s -> do x <- m<br />
> return (x,s))<br />
<br />
</haskell><br />
<br />
StateT is pleased to meet you!.<br />
<br />
===StateT as a counter, and monadic evaluator with output and exceptions===<br />
And now out monad, with state out from it:<br />
<br />
<haskell><br />
<br />
> data MTa a = FailTa Exception<br />
> | DoneTa {unpackDoneTa :: (a,O) }<br />
> deriving (Show)<br />
<br />
<br />
> instance Monad MTa where<br />
> return a = DoneTa (a, "")<br />
> m >>= f = case m of<br />
> FailTa e -> FailTa e<br />
> DoneTa (a, x) -> case (f a) of<br />
> FailTa e1 -> FailTa e1 <br />
> DoneTa (b, y) -> DoneTa (b, x ++ y) <br />
<br />
> instance Functor MTa where<br />
> fmap _ (FailTa e) = FailTa e<br />
> fmap f (DoneTa (r,o)) = DoneTa ((f r),o)<br />
<br />
> raiseTa_SIOE :: O -> StateT Int MTa a<br />
> raiseTa_SIOE e = lift (FailTa e)<br />
<br />
> printTa_SIOE :: O -> StateT Int MTa ()<br />
> printTa_SIOE x = lift (DoneTa ((), x))<br />
<br />
> incTaState :: StateT Int MTa ()<br />
> incTaState = StateT (\s -> return ((), s + 1))<br />
<br />
> evalTa_SIOE :: Term -> StateT Int MTa Int<br />
> evalTa_SIOE (Con a) = do incTaState<br />
> printTa_SIOE (formatLine (Con a) a)<br />
> return a<br />
> evalTa_SIOE (Add t u) = do a <- evalTa_SIOE t<br />
> b <- evalTa_SIOE u<br />
> incTaState<br />
> let out = formatLine (Add t u) (a + b)<br />
> printTa_SIOE out<br />
> if (a+b) == 42<br />
> then raiseTa_SIOE $ <br />
> out ++ "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
> runEvalTa :: Term -> String<br />
> runEvalTa exp = case runStateT (evalTa_SIOE exp) 0 of <br />
> FailTa e -> e<br />
> DoneTa (~(r,s),o)-> "Result = " ++ show r ++ <br />
> "; Iteration = " ++ show s ++ <br />
> "; Output = " ++ o<br />
<br />
> runEvalTa1 :: Term -> String<br />
> runEvalTa1 exp = case runState 0 (evalTa_SIOE exp) of <br />
> FailTa e -> e<br />
> DoneTa ((r,s),o) -> "Result = " ++ show r ++ <br />
> "; Iteration = " ++ show s ++ <br />
> "; Output = " ++ o<br />
<br />
> runEvalTa2 :: Term -> String<br />
> runEvalTa2 exp = case evalState 0 (evalTa_SIOE exp) of <br />
> FailTa e -> e<br />
> DoneTa (r,o) -> "Result = " ++ show r ++ "; Output = " ++ o<br />
<br />
> runEvalTa3 :: Term -> String<br />
> runEvalTa3 exp = case execState 0 (evalTa_SIOE exp) of <br />
> FailTa e -> e<br />
> DoneTa (s,o) -> "Iterations = " ++ show s ++ "; Output = " ++ o <br />
<br />
</haskell><br />
<br />
===StateT to keep output and counter, and monadic evaluator with (only) exceptions===<br />
<br />
Now we take output away from the inner monad and place it in the outer<br />
one (StateT):<br />
<br />
<haskell><br />
<br />
<br />
> data MTb a = FailTb Exception<br />
> | DoneTb {unpackDoneTb :: a }<br />
> deriving (Show)<br />
<br />
> type StateIO = (O,Int)<br />
<br />
> instance Monad MTb where<br />
> return a = DoneTb a<br />
> m >>= f = case m of<br />
> FailTb e -> FailTb e<br />
> DoneTb a -> f a<br />
<br />
> instance Functor MTb where<br />
> fmap _ (FailTb e) = FailTb e<br />
> fmap f (DoneTb b) = DoneTb (f b)<br />
<br />
<br />
> raiseTb_SIOE :: O -> StateT StateIO MTb a<br />
> raiseTb_SIOE e = lift (FailTb e)<br />
<br />
> printTb_SIOE :: O -> StateT StateIO MTb ()<br />
> printTb_SIOE x = StateT (\(o,s) -> return ((), (o ++ x,s)))<br />
<br />
> incTbStateIO :: StateT StateIO MTb ()<br />
> incTbStateIO = StateT (\(o,s) -> return ((), (o,s + 1)))<br />
<br />
> evalTb_SIOE :: Term -> StateT StateIO MTb Int<br />
> evalTb_SIOE (Con a) = do incTbStateIO<br />
> printTb_SIOE (formatLine (Con a) a)<br />
> return a<br />
> evalTb_SIOE (Add t u) = do a <- evalTb_SIOE t<br />
> b <- evalTb_SIOE u<br />
> incTbStateIO<br />
> let out = formatLine (Add t u) (a + b)<br />
> printTb_SIOE out<br />
> if (a+b) == 42<br />
> then raiseTb_SIOE $ <br />
> out ++ "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
</haskell><br />
<br />
We take away complexity from >>= and put it in the function we need<br />
to use to manipulate content in our StateT monad.<br />
<br />
These are some wrapper to the evaluator to get the result and the<br />
side-effects produced by evaluation:<br />
<br />
<haskell><br />
<br />
> runEvalTb :: Term -> String<br />
> runEvalTb exp = case runStateT (evalTb_SIOE exp) ("",0) of<br />
> FailTb e -> e<br />
> DoneTb (r,~(o,s)) -> "Result = " ++ show r ++ <br />
> "; Iteration = " ++ show s ++ <br />
> "; Output = " ++ o<br />
<br />
<br />
> runEvalTb1 :: Term -> String<br />
> runEvalTb1 exp = case runState ("",0) (evalTb_SIOE exp) of <br />
> FailTb e -> e<br />
> DoneTb (r,~(o,s)) -> "Result = " ++ show r ++ <br />
> "; Iteration = " ++ show s ++ <br />
> "; Output = " ++ o<br />
<br />
> runEvalTb2 :: Term -> String<br />
> runEvalTb2 exp = case evalState ("",0) (evalTb_SIOE exp) of <br />
> FailTb e -> e<br />
> DoneTb r -> "Result = " ++ show r<br />
<br />
> runEvalTb3 :: Term -> String<br />
> runEvalTb3 exp = case execState ("",0) (evalTb_SIOE exp) of <br />
> FailTb e -> e<br />
> DoneTb (o,s) -> "Iterations = " ++ show s ++ <br />
> " - Output = " ++ o<br />
<br />
</haskell><br />
<br />
===StateT to keep output, counter and debug. The monadic evaluator is only for failable computations===<br />
<br />
And now we will keep in the inner monad only the result of the evaluation.<br />
<br />
<haskell><br />
<br />
> data MT a = FailT Exc<br />
> | DoneT {unpackDoneT :: a }<br />
> deriving (Show)<br />
<br />
> type Exc = String<br />
> type IOstack = [Output]<br />
> newtype StateTIO = StateTIO {unPackStateTIO :: (IOstack,Exc,Int)}<br />
> deriving(Show)<br />
<br />
> instance Monad MT where<br />
> return a = DoneT a<br />
> m >>= f = case m of<br />
> FailT e -> FailT e<br />
> DoneT a -> f a<br />
<br />
> instance Functor MT where<br />
> fmap _ (FailT a) = FailT a<br />
> fmap f (DoneT a) = DoneT (f a)<br />
<br />
</haskell><br />
<br />
Simple isn't it?<br />
<br />
The complexity is now below:<br />
<br />
<haskell><br />
<br />
> stopExecT_SIOE :: Output -> StateT StateTIO MT Int<br />
> stopExecT_SIOE exc = StateT (\s -> do x <- FailT exc<br />
> return (x, s))<br />
<br />
> catchT_SIOE exc = StateT (\(StateTIO (o,e,s)) -> <br />
> return ((), StateTIO (o ,"Exception at Iteration " ++<br />
> show s ++ ": " ++ exc ++ " - " ++ e,s)))<br />
<br />
> printT_SIOE :: Output -> StateT StateTIO MT ()<br />
> printT_SIOE x = StateT (\(StateTIO (o,e,s)) -> return ((), StateTIO (x:o,e,s)))<br />
<br />
> incTstateIO :: StateT StateTIO MT ()<br />
> incTstateIO = StateT (\(StateTIO (o,e,s)) -> return ((),StateTIO (o,e,s + 1)))<br />
<br />
> evalT_SIOE :: Term -> StateT StateTIO MT Int<br />
> evalT_SIOE (Con a) = do incTstateIO<br />
> printT_SIOE (formatLine (Con a) a)<br />
> return a<br />
> evalT_SIOE (Add t u) = do a <- evalT_SIOE t<br />
> b <- evalT_SIOE u<br />
> incTstateIO<br />
> let out = formatLine (Add t u) (a + b)<br />
> printT_SIOE out<br />
> case (a+b) of <br />
> 42 -> do catchT_SIOE "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> return (a+b)<br />
> 11 -> stopExecT_SIOE "11.... I do not like this number!"<br />
> otherwise -> return (a + b)<br />
<br />
</haskell><br />
<br />
But now we have exceptions to stop execution and debugging output.<br />
<br />
Some helper functions:<br />
<br />
<haskell><br />
<br />
> runEvalT :: Term -> String<br />
> runEvalT exp = case runStateT (evalT_SIOE exp) (StateTIO ([],"",0)) of<br />
> FailT e -> e<br />
> DoneT (r,StateTIO (o,e,s)) -> "Result = " ++ show r ++ "; Iteration = " ++ show s ++ <br />
> "; Output = " ++ show o ++ " - Exceptions = " ++ e<br />
<br />
<br />
> runEvalT1 :: Term -> String<br />
> runEvalT1 exp = case runState (StateTIO ([],"",0)) (evalT_SIOE exp) of <br />
> FailT e -> e<br />
> DoneT (r,StateTIO(o,e,s)) -> "Result = " ++ show r ++ "; Iteration = " ++ show s <br />
> ++ "; Output = " ++ show o ++ " - Exceptions = " ++ e<br />
<br />
> runEvalT2 :: Term -> String<br />
> runEvalT2 exp = case evalState (StateTIO ([],"",0)) (evalT_SIOE exp) of <br />
> FailT e -> e<br />
> DoneT r -> "Result = " ++ show r<br />
<br />
> runEvalT3 :: Term -> String<br />
> runEvalT3 exp = case execState (StateTIO ([],"",0)) (evalT_SIOE exp) of <br />
> FailT e -> e<br />
> DoneT (StateTIO (o,e,s)) -> "Iterations = " ++ show s ++ <br />
<br />
> " - Output = " ++ show o ++ " - Exceptions = " ++ e<br />
> showOut :: [String] -> IO ()<br />
> showOut [] = return ()<br />
> showOut (a:xs) = do print a<br />
> showOut xs<br />
<br />
> runMyEval :: Term -> IO ()<br />
> runMyEval exp = let StateTIO (a,b,c) = unpackDoneT $ execState (StateTIO ([],"",0)) (evalT_SIOE exp) in<br />
> showOut $ reverse a<br />
<br />
</haskell><br />
<br />
Some tests:<br />
<pre><br />
*TheMonadicWay> runEvalT (Add (Con 18) (Add (Con 12) (Add (Con 10) (Con 2))))<br />
"Result = 42; Iteration = 7; Output = [\"eval (Add (Con 18) (Add (Con 12) (Add (Con 10) (Con 2)))) <= 42 - \",<br />
\"eval (Add (Con 12) (Add (Con 10) (Con 2))) <= 24 - \",<br />
\"eval (Add (Con 10) (Con 2)) <= 12 - \",<br />
\"eval (Con 2) <= 2 - \",<br />
\"eval (Con 10) <= 10 - \",<br />
\"eval (Con 12) <= 12 - \",<br />
\"eval (Con 18) <= 18 - \"] - <br />
Exceptions = Exception at Iteration 7: The Ultimate Answer Has Been Computed!! Now I'm tired! - "<br />
*TheMonadicWay> runEvalT2 (Add (Con 18) (Add (Con 12) (Add (Con 10) (Con 2))))<br />
"Result = 42"<br />
*TheMonadicWay> runEvalT3 (Add (Con 18) (Add (Con 12) (Add (Con 10) (Con 2))))<br />
"Iterations = 7 - Output = [\"eval (Add (Con 18) (Add (Con 12) (Add (Con 10) (Con 2)))) <= 42 - \",<br />
\"eval (Add (Con 12) (Add (Con 10) (Con 2))) <= 24 - \",<br />
\"eval (Add (Con 10) (Con 2)) <= 12 - \",<br />
\"eval (Con 2) <= 2 - \",<br />
\"eval (Con 10) <= 10 - \",<br />
\"eval (Con 12) <= 12 - \",<br />
\"eval (Con 18) <= 18 - \"] - <br />
Exceptions = Exception at Iteration 7: The Ultimate Answer Has Been Computed!! Now I'm tired! - "<br />
*TheMonadicWay> runEvalT3 (Add (Con 1) (Add (Con 7) (Add (Con 1) (Con 2))))<br />
"Iterations = 7 - Output = [\"eval (Add (Con 1) (Add (Con 5) (Add (Con 1) (Con 2)))) <= 9 - \",<br />
\"eval (Add (Con 5) (Add (Con 1) (Con 2))) <= 8 - \",<br />
\"eval (Add (Con 1) (Con 2)) <= 3 - \",<br />
\"eval (Con 2) <= 2 - \",<br />
\"eval (Con 1) <= 1 - \",<br />
\"eval (Con 5) <= 5 - \",<br />
\"eval (Con 1) <= 1 - \"] - Exceptions = "<br />
*TheMonadicWay> runEvalT3 (Add (Con 1) (Add (Con 7) (Add (Con 1) (Con 2))))<br />
"11.... I do not like this number!"<br />
*TheMonadicWay> runMyEval (Add (Add (Add (Add (Con 10) (Con 2)) (Add (Con 12) (Con 3))) (Con 3)) (Con 10))<br />
"eval (Con 10) <= 10 - "<br />
"eval (Con 2) <= 2 - "<br />
"eval (Add (Con 10) (Con 2)) <= 12 - "<br />
"eval (Con 12) <= 12 - "<br />
"eval (Con 3) <= 3 - "<br />
"eval (Add (Con 12) (Con 3)) <= 15 - "<br />
"eval (Add (Add (Con 10) (Con 2)) (Add (Con 12) (Con 3))) <= 27 - "<br />
"eval (Con 3) <= 3 - "<br />
"eval (Add (Add (Add (Con 10) (Con 2)) (Add (Con 12) (Con 3))) (Con 3)) <= 30 - "<br />
"eval (Con 10) <= 10 - "<br />
"eval (Add (Add (Add (Add (Con 10) (Con 2)) (Add (Con 12) (Con 3))) (Con 3)) (Con 10)) <= 40 - "<br />
*TheMonadicWay><br />
</pre><br />
<br />
<br />
==The final cut==<br />
<br />
===StateT for output, counter, debug, using the standard library===<br />
<br />
<haskell><br />
module MyStateT where<br />
import Control.Monad.State hiding (State)<br />
<br />
data Term = Con Int<br />
| Add Term Term<br />
deriving (Show)<br />
<br />
type IOStack = [Output]<br />
type Output = String<br />
type Debug = [String]<br />
data EvalST = State {getIOS :: IOStack, getDebug :: Debug, getCount:: Int}<br />
deriving(Show)<br />
<br />
<br />
type Exception = String<br />
data MT a = Fail Exception<br />
| Done {unpackDone :: a }<br />
deriving (Show)<br />
<br />
type Eval s a = StateT s MT a<br />
<br />
instance Monad MT where<br />
return a = Done a<br />
m >>= f = case m of<br />
Fail e -> Fail e<br />
Done a -> f a<br />
<br />
instance Functor MT where<br />
fmap _ (Fail a) = Fail a<br />
fmap f (Done a) = Done (f a)<br />
<br />
emptyState = State [] [] 0<br />
<br />
stopExecT exc = lift $ Fail exc<br />
<br />
catchT e = do st <- get<br />
let s = getCount st<br />
let es = getDebug st<br />
let o = getIOS st<br />
let exc = "Debug msg at Iteration " ++ show s ++ ": " ++ e<br />
put $ State o (exc:es) s<br />
<br />
printT :: Output -> Eval EvalST ()<br />
printT o = do st <- get<br />
let s = getCount st<br />
let e = getDebug st<br />
let os = getIOS st<br />
let out = show s ++ " - " ++ o<br />
put $ State (out:os) e s<br />
<br />
incTcounter :: Eval EvalST ()<br />
incTcounter = do st <- get<br />
let s = getCount st<br />
let e = getDebug st<br />
let o = getIOS st<br />
put $ State o e (s+1)<br />
<br />
evalT :: Term -> Eval EvalST Int<br />
evalT (Con a) = do incTcounter<br />
printT (formatLine (Con a) a)<br />
return a<br />
evalT (Add t u) = do a <- evalT t<br />
b <- evalT u<br />
incTcounter<br />
let out = formatLine (Add t u) (a + b)<br />
printT out<br />
case (a+b) of <br />
42 -> do catchT "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
return (a+b)<br />
11 -> stopExecT "11.... I do not like this number!"<br />
otherwise -> return (a + b)<br />
<br />
<br />
formatLine :: Term -> Int -> Output<br />
formatLine t a = "eval (" ++ show t ++ ") <= " ++ show a <br />
<br />
printAll :: [String] -> IO ()<br />
printAll [] = return ()<br />
printAll (a:xs) = do putStrLn a<br />
printAll xs<br />
<br />
eval :: Term -> IO ()<br />
eval exp = case execStateT (evalT exp) emptyState of<br />
Fail e -> putStrLn e<br />
Done (State a b c )<br />
-> do printAll $ reverse a<br />
putStrLn $ show $ unpackDone $ <br />
evalStateT (evalT exp) emptyState<br />
case b of<br />
[] -> putStrLn $ "Iterations: " ++ show c<br />
_ -> do printAll $ reverse b<br />
putStrLn $ "Iterations: " ++ show c<br />
<br />
---- testing functions ----<br />
runEvalT :: Term -> String<br />
runEvalT exp = case runStateT (evalT exp) emptyState of<br />
Fail e -> e<br />
Done (r,State o e s) -> "Result = " ++ show r ++ <br />
"; Iteration = " ++ show s ++ <br />
"; Output = " ++ show o ++<br />
" - Exceptions = " ++ show e<br />
<br />
getEvalResult :: Term -> String<br />
getEvalResult exp = case evalStateT (evalT exp) emptyState of <br />
Fail e -> e<br />
Done r -> "Result = " ++ show r<br />
<br />
<br />
getSideEffects :: Term -> String<br />
getSideEffects exp = case execStateT (evalT exp) emptyState of <br />
Fail e -> e<br />
Done (State o e s) -> "Iterations = " ++ show s ++ <br />
" - Output = " ++ show o ++ <br />
" - Exceptions = " ++ show e<br />
<br />
{-<br />
Some runs:<br />
<br />
*MyStateT> eval (Add (Add (Add (Add (Con 40) (Con 2)) (Add (Con 12) (Con 30))) (Con 3)) (Con 10))<br />
1 - eval (Con 40) <= 40<br />
2 - eval (Con 2) <= 2<br />
3 - eval (Add (Con 40) (Con 2)) <= 42<br />
4 - eval (Con 12) <= 12<br />
5 - eval (Con 30) <= 30<br />
6 - eval (Add (Con 12) (Con 30)) <= 42<br />
7 - eval (Add (Add (Con 40) (Con 2)) (Add (Con 12) (Con 30))) <= 84<br />
8 - eval (Con 3) <= 3<br />
9 - eval (Add (Add (Add (Con 40) (Con 2)) (Add (Con 12) (Con 30))) (Con 3)) <= 87<br />
10 - eval (Con 10) <= 10<br />
11 - eval (Add (Add (Add (Add (Con 40) (Con 2)) (Add (Con 12) (Con 30))) (Con 3)) (Con 10)) <= 97<br />
97<br />
Debug msg at Iteration 3: The Ultimate Answer Has Been Computed!! Now I'm tired!<br />
Debug msg at Iteration 6: The Ultimate Answer Has Been Computed!! Now I'm tired!<br />
Iterations: 11<br />
*MyStateT> <br />
<br />
*MyStateT> eval (Add (Add (Add (Add (Con 10) (Con 2)) (Add (Con 12) (Con 3))) (Add (Con 5) (Con 2))) (Con 2))<br />
1 - eval (Con 10) <= 10<br />
2 - eval (Con 2) <= 2<br />
3 - eval (Add (Con 10) (Con 2)) <= 12<br />
4 - eval (Con 12) <= 12<br />
5 - eval (Con 3) <= 3<br />
6 - eval (Add (Con 12) (Con 3)) <= 15<br />
7 - eval (Add (Add (Con 10) (Con 2)) (Add (Con 12) (Con 3))) <= 27<br />
8 - eval (Con 5) <= 5<br />
9 - eval (Con 2) <= 2<br />
10 - eval (Add (Con 5) (Con 2)) <= 7<br />
11 - eval (Add (Add (Add (Con 10) (Con 2)) (Add (Con 12) (Con 3))) (Add (Con 5) (Con 2))) <= 34<br />
12 - eval (Con 2) <= 2<br />
13 - eval (Add (Add (Add (Add (Con 10) (Con 2)) (Add (Con 12) (Con 3))) (Add (Con 5) (Con 2))) (Con 2)) <= 36<br />
36<br />
Iterations: 13<br />
*MyStateT> <br />
<br />
*MyStateT> eval (Add (Con 5) (Con 6))<br />
11.... I do not like this number!<br />
*MyStateT> <br />
-}<br />
</haskell><br />
<br />
== Next?==<br />
We need a parser to get a string from input and turn into something of type Term!<br />
<br />
Let's see if we'll time for it... Fist we must complete the text above!!<br />
<br />
==Suggested readings==<br />
<br />
Cale Gibbard, [http://haskell.org/haskellwiki/Monads_as_Containers Monads as Containers]<br />
<br />
Jeff Newbern, [http://haskell.org/all_about_monads/html/contmonad.html All About Monads]<br />
<br />
[http://haskell.org/haskellwiki/IO_inside IO Inside]<br />
<br />
[http://sigfpe.blogspot.com/2006/08/you-could-have-invented-monads-and.html You Could Have Invented Monads! (And Maybe You Already Have.) by sigfpe]<br />
<br />
<br />
==Acknowledgments==<br />
<br />
Thanks to Neil Mitchell, Daniel Fisher, Bulat Ziganzhin, Brian Hulley<br />
and Udo Stenzel for the invaluable help they gave, in the<br />
[http://www.haskell.org/mailman/listinfo/haskell-cafe haskell-cafe mailing list], <br />
in understanding this topic.<br />
<br />
I couldn't do it without their help.<br />
<br />
Obviously errors are totally mine. But this is a wiki so, please,<br />
correct them!<br />
<br />
- [[User:AndreaRossato|Andrea Rossato]]<br />
<br />
[[Category:Tutorials]]<br />
[[Category:Monad]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=The_Monadic_Way_Part_II&diff=14659The Monadic Way Part II2007-07-24T22:33:21Z<p>BrettGiles: The Monadic Way Part II moved to The Monadic Way/Part II: Makes sense as a sub-page</p>
<hr />
<div>#redirect [[The Monadic Way/Part II]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=The_Monadic_Way/Part_I&diff=14656The Monadic Way/Part I2007-07-24T22:32:40Z<p>BrettGiles: The Monadic Way Part I moved to The Monadic Way/Part I</p>
<hr />
<div>'''Note: this is the first part of [[The Monadic Way]]'''<br />
==An evaluation of Philip Wadler's "Monads for functional programming"==<br />
<br />
This tutorial is a "translation" of Philip Wadler's [http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf "Monads for functional programming"].<br />
(avail. from [http://homepages.inf.ed.ac.uk/wadler/topics/monads.html here])<br />
<br />
I'm a Haskell newbie trying to grasp such a difficult concept as the<br />
one of Monad and monadic computation.<br />
<br />
While [http://www.cs.utah.edu/~hal/htut/ "Yet Another Haskell Tutorial"] <br />
gave me a good understanding of the type system when it<br />
comes to monads I find it almost unreadable.<br />
<br />
But I had also Wadler's paper, and started reading it. Well, just<br />
wonderful! It explains how to ''create'' a monad!<br />
<br />
So I decided to "translate it", in order to clarify to myself the<br />
topic. And I'm now sharing this traslation ('''not completed yet'')<br />
with the hope it will be useful to someone else.<br />
<br />
Moreover, that's a wiki, so please improve it. And, specifically,<br />
correct my poor English. I'm Italian, after all.<br />
<br />
'''Note: The source of this page can be used as a Literate Haskell<br />
file and can be run with ghci or hugs: so cut paste change and run (in<br />
emacs for instance) while reading it...'''<br />
<br />
==A simple evaluator==<br />
<br />
Let's start with something simple: suppose we want to implement a new<br />
programming language. We just finished with<br />
[http://swiss.csail.mit.edu/classes/6.001/abelson-sussman-lectures/ Abelson and Sussman's Structure and Interpretation of Computer Programs] <br />
and we want to test what we have learned.<br />
<br />
Our programming language will be very simple: it will just compute the<br />
sum of two terms.<br />
<br />
So we have just one primitive operation (Add) that takes two constants<br />
and calculates their sum.<br />
<br />
Moreover we have just one kind of data type: Con a, which is an Int.<br />
<br />
For instance, something like:<br />
<br />
(Add (Con 5) (Con 6))<br />
<br />
should yield:<br />
<br />
11<br />
<br />
===The basic evaluator===<br />
<br />
We will implement our language with the help of a data type<br />
constructor such as:<br />
<br />
<div id="BasicEval"><br />
<haskell><br />
<br />
> module TheMonadicWay where<br />
> data Term = Con Int<br />
> | Add Term Term<br />
> deriving (Show)<br />
<br />
</haskell><br />
<br />
After that we build our interpreter:<br />
<br />
<haskell><br />
<br />
> eval :: Term -> Int<br />
> eval (Con a) = a<br />
> eval (Add a b) = eval a + eval b<br />
<br />
</haskell><br />
<br />
That's it. Just an example:<br />
<br />
*TheMonadicWay> eval (Add (Con 5) (Con 6))<br />
11<br />
*TheMonadicWay><br />
<br />
Very very simple. The evaluator checks if its argument is of type Con<br />
Int: if it is it just returns the Int.<br />
<br />
If the argument is not of type Con, but it is of type Term, it<br />
evaluates the first Term and sums the result with the result of the<br />
evaluation of the second Term.<br />
<br />
As you may understand, our evaluator uses some of the powerful<br />
features of Haskell type system. Instead of writing a parser that<br />
takes a string (the user input) and transforms that string into an<br />
expression to be evaluated, we use the two type constructors defined<br />
for our data type Term (Con and Add) to build the expression - such as<br />
(Add (Con 5) (Con 6)) - and to match the expression's elements in our<br />
"eval" function.<br />
<br />
<br />
== Some output, please!==<br />
<br />
Now, that's fine, but we'd like to add some features, like providing<br />
some output, to show how the computation was carried out.<br />
<br />
Well, but Haskell is a pure functional language, with no side effects,<br />
we were told.<br />
<br />
Now we seem to be wanting to create a side effect of the computation,<br />
its output, and be able to stare at it...<br />
<br />
If we had some global variable to store the out that would be<br />
simple...<br />
<br />
But we can create the output and carry it along the computation,<br />
concatenating it with the old one, and present it at the end of the<br />
evaluation together with the evaluation of the expression given to our<br />
evaluator/interpreter!<br />
<br />
===The basic evaluator with output===<br />
<br />
Simple and neat:<br />
<div id="BasivEvalO"><br />
<haskell><br />
<br />
> type MOut a = (a, Output)<br />
> type Output = String<br />
> <br />
> formatLine :: Term -> Int -> Output<br />
> formatLine t a = "eval (" ++ show t ++ ") <= " ++ show a ++ " - " <br />
> <br />
> evalO :: Term -> MOut Int<br />
> evalO (Con a) = (a, formatLine (Con a) a)<br />
> evalO (Add t u) = ((a + b),(x ++ y ++ formatLine (Add t u) (a + b)))<br />
> where (a, x) = evalO t<br />
> (b, y) = evalO u<br />
<br />
</haskell><br />
<br />
Now we have what we want. But we had to change our evaluator quite a<br />
bit. <br />
<br />
First we added a function, formatLine, that takes an argument of type<br />
Term (the expression to be evaluated), one of type Int (the result of<br />
the evaluation of Term) and gives back an output of type Output (that<br />
is a synonymous of String). This is just a helper function to format<br />
the string to output. Not very interesting at all.<br />
<br />
The evaluator itself changed quite a lot! Now it has a different type<br />
signature: it takes an argument of type Term and produces a new type,<br />
we called it MOut, that is actually a compound pair of a variable type<br />
a (an Int in our evaluator) and a type Output, a string.<br />
<br />
So our evaluator, now, will take a Term (the type of the expressions<br />
in our new programming language) and will produce a pair, composed of<br />
the result of the evaluation (an Int) and the Output, a string.<br />
<br />
So far so good. But what's happening inside the evaluator?<br />
<br />
The first part will just return a pair with the number evaluated ("a")<br />
and the output formatted by formatLine.<br />
<br />
The second part does something more complicated: it returns a pair<br />
composed by <br />
1. the result of the evaluation of the right Term summed to the result<br />
of the evaluation of the second Term<br />
2. the output: the concatenation of the output produced by the<br />
evaluation of the right Term, the output produced by the evaluation of<br />
the left Term (each this evaluation returns a pair with the number and<br />
the output), and the formatted output of the evaluation.<br />
<br />
Let's try it:<br />
*TheMonadicWay> evalO (Add (Con 5) (Con 6))<br />
(11,"eval (Con 5) <= 5 - eval (Con 6) <= 6 - eval (Add (Con 5) (Con 6)) <= 11 - ")<br />
*TheMonadicWay><br />
<br />
It works! Let's put the output this way:<br />
eval (Con 5) <= 5 - <br />
eval (Con 6) <= 6 - <br />
eval (Add (Con 5) (Con 6)) <= 11 -<br />
<br />
Great! We are able to produce a side effect of our evaluation and<br />
present it at the end of the computation, after all.<br />
<br />
Let's have a closer look at this expression:<br />
<haskell><br />
<br />
evalO (Add t u) = ((a + b),(x ++ y ++ formatLine (Add t u) (a + b)))<br />
where (a, x) = evalO t<br />
(b, y) = evalO u<br />
<br />
</haskell><br />
<br />
Why all that? The problem is that we need:<br />
* "a" and "b" to calculate their sum (a + b), that will be the first element of the compund pair rapresenting the type (MOut) our evaluator will return <br />
* "x and "y" (the output of each evaluation) to be concatenated with the ourput of formatLine by the expression (x ++ y ++ formatLine(...)): this will be the second element of the compound pair MOut, the string part.<br />
<br />
So we need to separate the pairs produced by "evalO t" and "evalO u".<br />
<br />
We do that within the where clause (remember: evalO now produces a value of type<br />
MOut Int, i.e. a pair of an Int and a String).<br />
<br />
Then we use the single element, "extraded" within the where clause, to<br />
return a new MOut composed by <br />
<br />
((a + b),(x ++ y ++ formatLine (Add t u) (a + b))).<br />
------ -------------------------------------<br />
Int Output = String<br />
<br />
== Let's go monadic==<br />
<br />
Is there a more general way of doing so?<br />
<br />
Let's analyze the evaluator from another perspective. From the type<br />
perspective.<br />
<br />
We solved our problem by creating a new type, a pair of an Int (the<br />
result of the evaluation) and a String (the output of the process of<br />
evaluation).<br />
<br />
The first part of the evaluator does nothing else but creating, from a<br />
value of type Int, an object of type MOut Int (Int,Output). It does so<br />
by creating a pair with that Int and some text produced by formatLine.<br />
<br />
The second part evaluates the two Term(s) and "stores" the values thus<br />
produced in some variables to be use later to compute the output.<br />
<br />
Let's focus on the "stores" action. The correct term should be<br />
"binds".<br />
<br />
Take a function:<br />
<haskell><br />
f x = x + x<br />
</haskell><br />
"x" appears on both sides of the expression. We say that on the right<br />
side "x" is bound to the value of x given on the left side.<br />
<br />
So<br />
<haskell><br />
f 3<br />
</haskell><br />
binds x to 3 for the evaluation of the expression "x + x".<br />
<br />
Our evaluator binds "a" and "x" / "b" and "y" with the evaluation of<br />
"evalO t" and "evalO u" respectively. <br />
<br />
Then "a","b","x" and "y" will be used in the evaluation of<br />
((a+b),(x++y++formatLine)), that will produce a value of type MOut Int:<br />
<br />
<pre><br />
<br />
((a + b),(x ++ y ++ formatLine (Add t u) (a + b))).<br />
------ -------------------------------------<br />
\ / \ /<br />
Int Output = String<br />
---------------------------------<br />
\ /<br />
MOut Int <br />
</pre><br />
<br />
The binding happens in the "where" clause:<br />
<haskell><br />
where (a, x) = evalO t<br />
(b, y) = evalO u<br />
</haskell><br />
<br />
We know that there is an ad hoc operator for binding variables to a<br />
value: lambda, or \.<br />
<br />
Indeed f x = x + x is syntactic sugar for:<br />
<haskell><br />
f = \x -> x + x<br />
</haskell><br />
When we write f 3 we are actually binding "x" to 3 within what's next<br />
"->", that will be used (substituted) for evaluating f 3.<br />
<br />
So we can try to abstract this phenomenon.<br />
<br />
===Monadic evaluator with output===<br />
What we need is a function that takes our composed type MOut Int and a<br />
function in order to produce a new MOut Int, concatenating the<br />
output of the computation of the first with the output of the<br />
computation of the second.<br />
<br />
This is what bindM does:<br />
<br />
<haskell><br />
<br />
> bindM :: MOut a -> (a -> MOut b) -> MOut b<br />
> bindM m f = (b, x ++ y)<br />
> where (a, x) = m<br />
> (b, y) = f a<br />
<br />
</haskell><br />
<br />
It takes:<br />
* "m": the compound type MOut Int carrying the result of an "eval Term",<br />
* a function "f". This function will take the Int ("a") extracted by the evaluation of "m" ((a,x)=m). This function will produce a new pair: a new Int produced by a new evaluation; some new output.<br />
<br />
bindM will return the new Int in pair with the concatenated outputs<br />
resulting from the evaluation of "m" and "f a".<br />
<br />
As you see, we took the binding part out from evalO and put it in this new function.<br />
<br />
So let's write the new version of the evaluator, that we will call evalM_1:<br />
<br />
<haskell><br />
<br />
> evalM_1 :: Term -> MOut Int<br />
> evalM_1 (Con a) = (a, formatLine (Con a) a)<br />
> evalM_1 (Add t u) = bindM (evalM_1 t) (\a -> <br />
> bindM (evalM_1 u) (\b -> <br />
> ((a + b), formatLine (Add t u) (a + b))<br />
> )<br />
> )<br />
<br />
</haskell><br />
<br />
Ugly, isn't it?<br />
<br />
Let's start from the outside:<br />
<br />
<haskell><br />
bindM (evalM_1 u) (\b -> ((a + b), formatLine (Add t u) (a + b)))<br />
</haskell><br />
<br />
bindM takes the result of the evaluation "evalM_1 u", a type Mout Int,<br />
and a function. It will extract the Int from that type and use it to<br />
bind "b".<br />
<br />
So in bindM (evalM_1 u) (\b ->) "b" will be bound to the value<br />
returned by evalM_1 u, and this bound variable will be available in<br />
what comes after "->" as a bound variable (not free).<br />
<br />
Then the outer part (bindM (evalM_1 t) (\a...) will bind "a" to the<br />
value returned "evalM_1 t", the result of the evaluatuion of the first<br />
Term. This value is needed to evaluate "((a+b), formatLine...) and<br />
produce our final MOut Int.<br />
<br />
We can try to explain "bindM" in a different way by using more descriptive names.<br />
<br />
As we have seen, "bindM" extracts the Int part from our type. The Int<br />
part will be used for further computations and the Output part will be<br />
concatenated. As a result we will have a new pair with a new Int and<br />
an accumulated Output.<br />
<br />
The new version of "bindM":<br />
<haskell><br />
<br />
> getIntFromType typeMOut doSomething = (newInt,oldOutput ++ newOutput)<br />
> where (oldInt,oldOutput) = typeMOut<br />
> (newInt,newOutput) = (doSomething oldInt)<br />
<br />
</haskell><br />
<br />
As you can see it does the very same things that "bindM" does: it<br />
takes something of type MOut and a function to perform some<br />
computation with the Int part. <br />
<br />
In the "where" clause, the old Int and the old output<br />
will be extracted from our type MOut (first line of the "where"<br />
clause). <br />
<br />
A new Int and a new output will be extracted from evaluating<br />
(doSomething oldInt) in the second line.<br />
<br />
Our function will return the new Int and the concatenated outputs.<br />
<br />
We do not need to define our doSomething function, because it will be<br />
an anonymous function:<br />
<br />
<haskell><br />
<br />
> evaluator (Con a) = (a, "output-")<br />
> evaluator (Add t u) = <br />
> getIntFromType (evaluator t) <br />
> (\firstInt -> getIntFromType (evaluator u) <br />
> (\secondInt -> ((firstInt + secondInt),("-newoutput"))))<br />
<br />
</haskell><br />
<br />
As you can see we are feeding our "getIntFromType" with the evaluation<br />
of an expression ("evaluator t" and "evaluator u"). The second<br />
argument of "getIntFromType" is an anonymous function that takes the<br />
"oldInt" and does something with it.<br />
<br />
So we have a series of nested anonymous functions. Their arguments<br />
("\firstInt" and "\secondInt") will be used to produce the computation<br />
we need ("(firstInt + secondInt). Moreover "getIntFromType" will take<br />
care of concatenating the outputs.<br />
<br />
This is the result:<br />
<br />
*TheMonadicWay> evaluator (Add (Con 5) (Con 6))<br />
(11,"output-output--newoutput")<br />
*TheMonadicWay> <br />
<br />
Going back to our "bindM", we can now use lambda notation to write our<br />
evaluator in a more convinient way:<br />
<br />
<haskell><br />
<br />
> evalM_2 :: Term -> MOut Int<br />
> evalM_2 (Con a) = (a, formatLine (Con a) a)<br />
> evalM_2 (Add t u) = evalM_2 t `bindM` \a -><br />
> evalM_2 u `bindM` \b -><br />
> ((a + b), (formatLine (Add t u) (a + b)))<br />
<br />
</haskell><br />
<br />
Now, look at the first part:<br />
<br />
<haskell><br />
evalM_2 (Con a) = (a, formatLine (Con a) a)<br />
</haskell><br />
<br />
We could use a more general way of creating some output. <br />
<br />
We can create a function that takes an Int and returns the type MOut<br />
Int. We do that by pairing the received Int with an empty string "".<br />
<br />
This will be a general way of creating an object with type MOut Int starting from an Int.<br />
<br />
Or, more generaly, a function that takes something of a variable type<br />
a, and return an object of type MOut a, a coumpunt object made up of<br />
an element of type a, and one of type String.<br />
<br />
There it is:<br />
<br />
<haskell><br />
<br />
> mkM :: a -> MOut a<br />
> mkM a = (a, "")<br />
<br />
</haskell><br />
<br />
As you can see, this function will just push an Int and an empty<br />
string ("") inside our type MOut.<br />
<br />
Then we need a method of inserting some text in our object of type<br />
MOut. So we will take a string and return it paired with a void<br />
element "()":<br />
<br />
<haskell><br />
<br />
> outPut :: Output -> MOut ()<br />
> outPut x = ((), x)<br />
<br />
</haskell><br />
<br />
Very simple: we have a string "x" (Output) and create a pair with a ()<br />
instead of an Int, and the output.<br />
<br />
You can see this function as one that pushes a string, paired with a<br />
void int, inside our type MOut.<br />
<br />
Now we can rewrite:<br />
<haskell><br />
evalM_2 (Con a) = (a, formatLine (Con a) a)<br />
</haskell><br />
using the bindM function:<br />
<haskell><br />
evalM_2 (Con a) = outPut (formatLine (Con a) a) `bindM` \_ -> mkM a<br />
</haskell><br />
<br />
First we create an object of type MOut with the Int part (). As you<br />
see bindM will not use it ("\_"), but will concatenate the String part<br />
with the result of mkM, which in turn is the empty string "".<br />
<br />
In other words, first we insert the Output part (a string) in our<br />
MOut, and then we insert the Int paired with an empty string: "bindM"<br />
will not use the void int (the anonymous function will not use it's<br />
argument: "\_"), but will take care of concatenating the non empty<br />
string inserted by "outPut" with the empty one inserted by "mkM".<br />
<br />
Let's rewrite the evaluator:<br />
<br />
<haskell><br />
<br />
> evalM_3 :: Term -> MOut Int<br />
> evalM_3 (Con a) = outPut (formatLine (Con a) a) `bindM` \_ -> <br />
> mkM a<br />
> evalM_3 (Add t u) = evalM_3 t `bindM` \a -><br />
> evalM_3 u `bindM` \b -><br />
> outPut (formatLine (Add t u) (a + b)) `bindM` \_ -> <br />
> mkM (a + b)<br />
<br />
</haskell><br />
<br />
Well, this is fine, definetly better then before, anyway.<br />
<br />
Still we use `bindM` \_ -> that binds something we do not use (_). We<br />
could write a function for this specific case, when we concatenate<br />
computations without the need of binding variables for later uses.<br />
Let's call it `combineM`:<br />
<br />
<haskell><br />
<br />
> combineM :: MOut a -> MOut b -> MOut b<br />
> combineM m f = m `bindM` \_ -> f<br />
<br />
</haskell><br />
<br />
This is just something that will allow us to write the evaluator in a<br />
more concise way. <br />
<br />
So the new evaluator:<br />
<br />
<haskell><br />
<br />
> evalM :: Term -> MOut Int<br />
> evalM (Con a) = outPut (formatLine (Con a) a) `combineM` <br />
> mkM a<br />
> evalM (Add t u) = evalM t `bindM` \a -><br />
> evalM u `bindM` \b -><br />
> outPut (formatLine (Add t u) (a + b)) `combineM` <br />
> mkM (a + b)<br />
<br />
</haskell><br />
<br />
Let's put everything together (changing M into MO, so that this file<br />
will be still usable as a Literate Haskell file):<br />
<br />
<haskell><br />
<br />
> type MO a = (a, Out)<br />
> type Out = String<br />
<br />
> mkMO :: a -> MO a<br />
> mkMO a = (a, "")<br />
<br />
> bindMO :: MO a -> (a -> MO b) -> MO b<br />
> bindMO m f = (b, x ++ y)<br />
> where (a, x) = m<br />
> (b, y) = f a<br />
<br />
> combineMO :: MO a -> MO b -> MO b<br />
> combineMO m f = m `bindM` \_ -> f<br />
<br />
> outMO :: Out -> MO ()<br />
> outMO x = ((), x)<br />
<br />
> evalMO :: Term -> MO Int<br />
> evalMO (Con a) = outMO (formatLine (Con a) a) `combineMO`<br />
> mkMO a<br />
> evalMO (Add t u) = evalMO t `bindMO` \a -><br />
> evalMO u `bindMO` \b -><br />
> outMO (formatLine (Add t u) (a + b)) `combineMO` <br />
> mkMO (a + b)<br />
<br />
</haskell><br />
<br />
==What does bind bind?==<br />
<br />
<div id="Bind"><br />
The evaluator looks like:<br />
<haskell><br />
evalM t >>= \a -> evalM u >>= \b -> outPut "something" >>= \_ -> mkM (a +b)<br />
</haskell><br />
where >>= is bindMO, obviously.<br />
<br />
Let's do some substitution, writing the type of their output of each function:<br />
* evalMO t => (a,Out) - where a is Int<br />
* evalMO u => (b,Out) - where b is the same of a, an Int, but with a different value<br />
* outMO Out = ((),Out)<br />
* mkMO (a+b) => ((a+b),Out) - where (a+b) is the same of a and b, but with a different value from either a and b<br />
<br />
<pre><br />
B | (a,Out) >>= \a -> (b,Out) >>= \b -> ((),Out) >>= \_ >>= ((a + b), Out)---\<br />
i | V V V V V V V V ^ ^ ^ ^ |\<br />
n | |__|________^ | | ^ | | | | | | | MOut Int <=> ((a+b), Out)<br />
d |_____|__(++)__|_Out_|__|__(++)__V_Out_|___|___(++)_|_(++)__|___|____|_____|/<br />
i | | |______(b)__|_____|_____(b)____|__(b)__|___|<br />
n | |_________(a)___________|____________|__(a)__|<br />
g | |_____()_____|<br />
<br />
</pre><br />
<br />
Clear, isn't it?<br />
<br />
"bindMO" is just a function that takes care of gluing together, inside<br />
a data type, a sequence of computations!<br />
<br />
== Some sugar, please!==<br />
Now our evaluator has been completely transformed into a monadic<br />
evaluator. That's what it is: a monad.<br />
<br />
We have a function that constructs an object of type MO Int, formed by<br />
a pair: the result of the evaluation and the accumulated<br />
(concatenated) output.<br />
<br />
The process of accumulation and the act of parting the MO Int into its<br />
component is buried into bindMO, now, that can also preserve some<br />
value for later uses.<br />
<br />
So we have:<br />
* MO a type constructor for a type carrying a pair composed by an Int and a String;<br />
* bindMO, that gives a direction to the process of evaluation: it concatenates computations and captures some side effects we created (the direction is given by the changes in the Out part: there's a "before" when Out was something and there's a "later" when Out is something else).<br />
* mkMO lets us create an object of type MO Int starting from an Int.<br />
<br />
As you see this is all we need to create a monad. In other words<br />
monads arise from the type system and the lambda calculus. Everything<br />
else is just syntactic sugar.<br />
<br />
So, let's have a look at that sugar: the famous do-notation!<br />
<br />
===Monadic evaluator with output in do-notation===<br />
<br />
In order to be able to use the "do-notation" we need to define a new<br />
type and make it an instance of the Monad class. To make a new type an<br />
instance of the Monad class we will have to define the two methods of<br />
this class: (>>=) and "return".<br />
<br />
This is not going to be difficult, because we already created these<br />
two methods: "bindM" and "mkM". Now we will have to rewrite them in<br />
order to reflect the fact that we are not going to use a type, for our<br />
evaluator, that is a synonymous of other types, as we did before.<br />
Indeed our MOut was defined with the "type" keyword. Now we will have<br />
to define a "real" new type with either "newtype" or "data". Since we<br />
are not going to need multiple constructors, we will use "newtype".<br />
<br />
<div id="MonadicEvalIO"><br />
<haskell><br />
<br />
> newtype Eval_IO a = Eval_IO (a, O)<br />
> deriving (Show)<br />
> type O = String<br />
<br />
</haskell><br />
<br />
This is our new type: it will have a single type constructor, whose<br />
name is the same of the type name ("Eval_IO"). The type constructor<br />
takes a parameter ("a"), a variable type, and will build a type formed<br />
by a type "a" (an Int in our case) and a String (O is indeed<br />
synonymous of String).<br />
<br />
We now need to define our "bind" function to reflect the fact that we<br />
are now using a "real" type, and, to unpack its content, we need to do<br />
pattern-matching we the type constructor "Eval_IO". Moreover, since we<br />
must return an Eval_IO type, we will use the type constructor also for<br />
building the new type with the new int and the concatenated output.<br />
<br />
For the rest our "bind" function will be identical to the one we<br />
defined before.<br />
<br />
We are going to use very descriptive names:<br />
<br />
<haskell><br />
<br />
> getInt monad doSomething = Eval_IO (newInt,oldOutput ++ newOutput)<br />
> where Eval_IO (oldInt,oldOutput) = monad<br />
> Eval_IO (newInt,newOutput) = (doSomething oldInt)<br />
<br />
</haskell><br />
<br />
As you can see, we are using Eval_IO to build the result of the<br />
computation to be returned by getInt: "Eval_IO (newInt,oldOutput ++<br />
newOutput)". And we are using it to match the internal components of<br />
our type in the "where" clause.<br />
<br />
We also need to create a function that, like mkO, will take an Int and,<br />
using the type constructor "Eval_IO", will create an object of type<br />
Eval_IO with that Int and an empty string:<br />
<br />
<haskell><br />
<br />
> createEval_IO :: a -> Eval_IO a<br />
> createEval_IO int = Eval_IO (int,"")<br />
<br />
</haskell><br />
<br />
And, finally, we need a function that will insert, in our type, a<br />
string and a void ():<br />
<br />
<haskell><br />
<br />
> print_IO :: O -> Eval_IO ()<br />
> print_IO string = Eval_IO ((), string)<br />
<br />
</haskell> <br />
<br />
With these functions we could write our monadic evaluator without the<br />
"do-notation" like this:<br />
<br />
<haskell><br />
<br />
> evalM_4 :: Term -> Eval_IO Int<br />
> evalM_4 (Con a) = createEval_IO a<br />
> evalM_4 (Add t u) = evalM_4 t `getInt` \a -><br />
> evalM_4 u `getInt` \b -><br />
> print_IO (formatLine (Add t u) (a + b)) `getInt` \_ -><br />
> createEval_IO (a + b)<br />
<br />
</haskell><br />
<br />
It is very similar to the previous evaluator, as you can see. The only<br />
differences are related to the fact that we are now using a "real"<br />
type and not a type synonymous: this requires the use of the type<br />
constructor to match the type and its internal part (as we do in the<br />
"where" clause of our "bind" function: "getInt") or to build the type<br />
(as we do in the "bind" function to return the new Int with the<br />
concatenated output).<br />
<br />
Running this evaluator will produce:<br />
<br />
*TheMonadicWay> evalM_4 (Add (Con 6) (Con 12))<br />
Eval_IO (18,"eval (Add (Con 6) (Con 12)) <= 18 - ")<br />
*TheMonadicWay> <br />
<br />
Now we have everything we need to declare our type, Eval_IO, as an<br />
instance of the Monad class:<br />
<haskell><br />
<br />
> instance Monad Eval_IO where<br />
> return a = createEval_IO a<br />
> (>>=) m f = getInt m f<br />
<br />
</haskell><br />
<br />
As you see we are just using our defined functions as methods for our<br />
instance of the Monad class.<br />
<br />
This is all we need to do. Notice that we do not have to define the<br />
"combineM" function, for chaining computation, as we do with "getInt",<br />
without binding variables for later use within the series of nested<br />
anonymous functions (the "doSomething" part) that will form the "do"<br />
block.<br />
<br />
This function comes for free by just defining our type as an instance<br />
of the Monad class. Indeed, if you look at the definition of the Monad<br />
class in the Prelude you see that "combineM", or (>>) is deduced by<br />
the definition of (>>=):<br />
<br />
<haskell><br />
class Monad m where<br />
return :: a -> m a<br />
(>>=) :: m a -> (a -> m b) -> m b<br />
(>>) :: m a -> m b -> m b<br />
fail :: String -> m a<br />
<br />
-- Minimal complete definition: (>>=), return<br />
p >> q = p >>= \ _ -> q<br />
fail s = error s<br />
</haskell><br />
<br />
You can see that the "combineM"" method (or (>>)) is automatically<br />
derived by the "bindMO" (or >>=) method:<br />
<br />
<haskell><br />
p >> q = p >>= \ _ -> q<br />
</haskell><br />
<br />
We can now write our evaluator using the do-notation:<br />
<br />
<haskell><br />
<br />
> eval_IO :: Term -> Eval_IO Int<br />
> eval_IO (Con a) = do print_IO (formatLine (Con a) a)<br />
> return a<br />
> eval_IO (Add t u) = do a <- eval_IO t<br />
> b <- eval_IO u<br />
> print_IO (formatLine (Add t u) (a + b))<br />
> return (a + b)<br />
<br />
</haskell><br />
<br />
As you can see the anonymous functions are gone. Instead we use this:<br />
a <- eval_IO t<br />
<br />
This seems like an assignment, that cannot be possible in Haskell. In<br />
fact it is just the way our anonymous function's arguments is bound<br />
within a do block.<br />
<br />
Even if it does not seem like a series of nested anonymous functions,<br />
this is what actually a do block is.<br />
<br />
Our monad is defined by three elements: <br />
* a type, with its type constructor(s);<br />
* a bind method: it will bind an unwritten anonymous function's argument to the value of the Int part of our type, or more generally, of the variable type "a". It will also create a series of anonymous functions: a line for each function;<br />
* a "return" function, to insert, into out type, a value of type Int, or, more generally, a value of variable type "a".<br />
<br />
Additionally, we need a function to insert a string in our type,<br />
string that the derived "bind" (>>) will concatenate ignoring the void<br />
(), our "print_IO".<br />
<br />
Within a do block we can thus perform only tree kinds of operations:<br />
* a computation that produces a new Int, packed inside our monad's type, to be extracted and bound to a variable (an anonymous function's argument really):<br />
** this operation requires a binding (">>= \varName ->"), translated into "varName <- computation"<br />
** example: a <- eval_IO t<br />
* a computation that inserts a string into our monad, a string to be concatenated, without the need of binding a variable (an anonymous function's argument really):<br />
** this operation does not require a binding: it will be ">>= \_ ->", i.e. ">>", translated into a simple new line<br />
** example: print_IO (formatLine (Add t u) (a + b))<br />
* a computation that inserts an Int into our monad without the need of binding a variable (an anonymous function's argument really):<br />
** this operation is carried out by the <hask>return</hask> method (usually at the end of a do block, useless in the middle)<br />
** example <hask>return (a + b)</hask><br />
<br />
To sum up, within a block, "do" will take care of creating and<br />
nesting, for us, all the needed anonymous functions so that bound<br />
variables will be available for later computations.<br />
<br />
In this way we can emulate a direction of our computation, a "before"<br />
and an "after", even within a pure functional language. And we can use<br />
this possibility to create and accumulate side effects, like output.<br />
<br />
Let's see the evaluator with output in action:<br />
*TheMonadicWay> eval_IO (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <br />
Eval_IO (54,"eval (Con 6) <= 6 - eval (Con 16) <= 16 - eval (Con 20) <= 20 - eval (Con 12) <= 12 - \<br />
eval (Add (Con 20) (Con 12)) <= 32 - eval (Add (Con 16) (Add (Con 20) (Con 12))) <= 48 - \<br />
eval (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <= 54 - ")<br />
*TheMonadicWay> <br />
<br />
Let's format the output part:<br />
eval (Con 6) <= 6 <br />
eval (Con 16) <= 16 <br />
eval (Con 20) <= 20 <br />
eval (Con 12) <= 12 <br />
eval (Add (Con 20) (Con 12)) <= 32 <br />
eval (Add (Con 16) (Add (Con 20) (Con 12))) <= 48 <br />
eval (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <= 54 <br />
<br />
==[[Type]] and [[Newtype]]: What happened to our output?==<br />
<br />
Well, actually something happened to the output. Let's compare the<br />
output of evalMO (the monadic evaluator written without the<br />
do-notation) and eval_IO:<br />
<br />
*TheMonadicWay> evalMO (Con 6)<br />
(6,"eval (Con 6) <= 6 - ")<br />
*TheMonadicWay> eval_IO (Con 6)<br />
Eval_IO (6,"eval (Con 6) <= 6 - ")<br />
*TheMonadicWay> <br />
<br />
They look almost the same, but they are not the same: the output of<br />
eval_IO has the Eval_IO stuff. It must be related to the changes we<br />
had to do to our evaluator in order to use the do-conation, obviously.<br />
<br />
We can now review some of our basic knowledge of Haskell's type<br />
system.<br />
<br />
What's changed? First the type definition. We have now:<br />
<br />
<haskell><br />
newtype Eval_IO a = Eval_IO (a, O)<br />
deriving (Show)<br />
</haskell><br />
<br />
instead of <br />
<br />
<haskell><br />
type MO a = (a, Out)<br />
</haskell><br />
<br />
Now <hask>return a</hask> is the product of the application of the<br />
type constructor Eval_IO to the pair that are going to form our monad.<br />
<br />
"return" takes an Int and inserts it into our monad. It will also<br />
insert an empty String "" that (>>=) or (>>) will then concatenate in<br />
the sequence of computations they glue together.<br />
<br />
The same for (>>=). It will now return something constructed by<br />
Eval_IO: <br />
<br />
* "newInt", the result of the application of "doSomething" to "oldInt" (better, the binding of "oldInt" in "doSomething");<br />
* the concatenation of "oldOutput" (matched by <hask>Eval_IO (oldInt, oldOutput)</hask> with the evaluation of "monad" - "eval_IO t") and "newOutput", (matched by "Eval_IO(newInt,newOutput)" with the evaluation of "(doSomething monad)" - "eval_IO u").<br />
<br />
That is to say: in the "where" clause, we are matching for the<br />
elements paired in a type Eval_IO: this is indeed the type of "monad"<br />
(corresponding to "eval_IO t" in the body of the evaluator) and<br />
"(doSomething monad)" (where "doSomething" correspond to the<br />
evaluation of "eval_IO u" within an anonymous function with \oldInt as<br />
its argument, argument bound to the result of the previous evaluation<br />
of "monad", that is to say "eval_IO t").<br />
<br />
And so, "Eval_IO (oldInt,oldOutput) = monad" means: match "oldInt" and<br />
"oldOutput", paired in a type Eval_IO, and that are produced by the<br />
evaluation of "monad" (that is to say: "eval_IO t"). The same for<br />
Eval_IO (newInt,newOutput): match "newInt" and "newOutput" produced by<br />
the evaluation of "(doSomething monad)".<br />
<br />
So the output of the evaluator is now not simply a pair made of and<br />
Int and a String. It is a specific type (Eval_IO) that happens to<br />
carry a pair of an Int and a String. But, if we want the Int and the<br />
string, we have to extract them from the Eval_IO type, as we do in the<br />
"where" clause: we ''unpack'' our type object (let's call it with its<br />
name: our monad!) and take out the Int and the String to feed the next<br />
function application and the output generation.<br />
<br />
The same to insert something in our monad: if we want to create a pair<br />
of an Int and a String, pair of type Eval_IO, we now have to ''pack''<br />
them together by using our type constructor, feeding it with a pair<br />
composed by and Int and a String. This is what we do with the "return"<br />
method of out monad and with "print_IO" function, where:<br />
* return insert into the monad an Int;<br />
* print_IO insert into the monad a String.<br />
<br />
So, why cannot we use the old <hask>type MO a = (a, Out)</hask> that<br />
did not required all this additional work (apart the need to<br />
specifically define (>>)?<br />
<br />
Type MO is just a synonymous for (a,Out): the two can be substituted<br />
one for the other. That's it.<br />
<br />
We did not have to pack "a" and "Out" together with a type constructor<br />
to have a new type MO.<br />
<br />
As a consequence, we cannot use MO as an instance of Monad, and so, we<br />
cannot use with it the syntactic sugar we needed: the do-notation.<br />
<br />
That is to say: a type created with the "type" keyword cannot be an<br />
instance of a class, and cannot inherits its methods (in our case<br />
(>>=, >> and return). And without those methods the do-notation is not<br />
usable.<br />
<br />
==Errare monadicum est==<br />
<br />
Now that we have a basic understanding of what a monad is, and does,<br />
we will further explore it by making some changes to our evaluator.<br />
<br />
In this section we will se how to handle exceptions in our monadic<br />
evaluator.<br />
<br />
Suppose that we want to stop the execution of our monad if some<br />
conditions occurs. If our evaluator was to compute divisions, instead<br />
of sums, then we would like to stop the evaluator when a division by<br />
zero occurs, possibly producing some output, instead of the result of<br />
the evaluation of the expression, that explains what happened.<br />
<br />
Basic error handling.<br />
<br />
We will do so starting from the beginning once again...<br />
<br />
===The basic evaluator, non monadic, with exception===<br />
<br />
We just take our basic evaluator, without any output, and write a<br />
method to stop execution if a condition occurs: <br />
<br />
<haskell><br />
<br />
> data M a = Raise Exception<br />
> | Return a<br />
> deriving (Show)<br />
> type Exception = String<br />
<br />
</haskell><br />
<br />
Now, our monad is of datatype "M a" which can either be constructed<br />
with the "Raise" constructor, that takes a String (Exception is a<br />
synonymous of String), or by the "Return" constructor, that takes a<br />
variable type ("a"), an Int in our case.<br />
<br />
<haskell><br />
<br />
> evalE :: Term -> M Int<br />
> evalE (Con a) = Return a<br />
<br />
</haskell><br />
<br />
If evalE matches a Con it will construct a type Return with, inside, the content of the Con.<br />
<br />
<haskell><br />
<br />
> evalE (Add a b) = <br />
> case evalE a of<br />
> Raise e -> Raise e<br />
> Return a -><br />
> case evalE b of <br />
> Raise e -> Raise e<br />
> Return b -><br />
> if (a+b) == 42<br />
> then Raise "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else Return (a+b)<br />
<br />
</haskell><br />
<br />
If evalE matches an Add it will check if evaluating the first part<br />
produces a "Raise" or a "Return": in the first case it will return a<br />
"Raise" whose content is the same received. <br />
<br />
If instead the evaluation produces a value of a type matched by<br />
"Return", the evaluator will evaluate the second term of Add.<br />
<br />
If this returns a "Raise", a "Raise" will be returned all the way up<br />
the recursion, otherwise the evaluator will check whether a condition<br />
for raising a "Raise" exists. If not, it will return a "Return" with<br />
the sum inside.<br />
<br />
Test it with:<br />
<br />
evalE (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2)))<br />
<br />
<br />
===The basic evaluator, monadic, with exceptions===<br />
<br />
In order to produce a monadic version of the previous evaluator, the<br />
one that raises exceptions, we just need to abstract out from the<br />
evaluator all that case analysis.<br />
<br />
<haskell><br />
<br />
> data M1 a = Except Exception<br />
> | Ok {showM :: a }<br />
> deriving (Show)<br />
<br />
</haskell><br />
<br />
The data type didn't change at all. Well, we changed the name of the<br />
Return type constructor (now Ok) so that this constructor can coexist<br />
with the previous one in the same Literate Haskell file.<br />
<br />
<div id="MonadicEvalE"><br />
<haskell><br />
<br />
> instance Monad M1 where<br />
> return a = Ok a<br />
> m >>= f = case m of<br />
> Except e -> Except e<br />
> Ok a -> f a<br />
<br />
</haskell><br />
<br />
Binding operations are now very easy. Basically we check:<br />
* if the result of the evaluation of "m" produces an exception (first match: Except e ->...), in which case we return its content by constructing our M1 Int with the "Raise" constructor".<br />
* if the result of the evaluation of "m" is matched with the "Ok" constructor, we get its content and use it to bind the argument of "f" to its value.<br />
<br />
<hask>return a</hask> will just use the Ok type constructor for<br />
inserting "a" (in our case an Int) into M1 Int, the type of our monad.<br />
<br />
<haskell><br />
<br />
> raise :: Exception -> M1 a<br />
> raise e = Except e<br />
<br />
</haskell><br />
<br />
This is just a helper function to construct our "M1 a" type with the<br />
Raise constructor. It takes a string and returns a type (M1 a) to be<br />
matched with the "Raise" constructor.<br />
<br />
<haskell><br />
<br />
> eval_ME :: Term -> M1 Int<br />
> eval_ME (Con a) = do return a<br />
> eval_ME (Add t u) = do a <- eval_ME t<br />
> b <- eval_ME u<br />
> if (a+b) == 42<br />
> then raise "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
</haskell><br />
<br />
The evaluator itself is very simple. We bind "a" with the result of<br />
"eval_ME t", "b" with the result of "eval_ME u", and we check for a<br />
condition: <br />
* if the condition is met we raise an exception, that is to say: we return a value constructed with the "Raise" constructor. This value will be matched by ">>=" in the next recursion. And >>= will just return it all the way up the recursion.<br />
* if the condition is not met, we return a value constructed with the "Return" type constructor and go on with the recursion.<br />
<br />
Run with:<br />
<br />
eval_ME (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2)))<br />
<br />
It is noteworthy the fact that in our datatype definition we used a<br />
label field with a label selector (we called it showM), even though it<br />
was not used in our code. We will use this methodology later on.<br />
<br />
So, just to refresh your memory:<br />
<br />
<haskell><br />
<br />
> data Person = Person {name :: String,<br />
> age :: Int,<br />
> hobby :: String<br />
> } deriving (Show)<br />
<br />
> andreaRossato = Person "Andrea" 37 "Haskell The Monadic Way"<br />
> personName (Person a b c) = a<br />
<br />
</haskell><br />
<br />
will produce:<br />
*TheMonadicWay> andreaRossato<br />
Person {name = "Andrea", age = 37, hobby = "Haskell The Monadic Way"}<br />
*TheMonadicWay> personName andreaRossato<br />
"Andrea"<br />
*TheMonadicWay> name andreaRossato<br />
"Andrea"<br />
*TheMonadicWay> age andreaRossato<br />
37<br />
*TheMonadicWay> hobby andreaRossato<br />
"Haskell The Monadic Way"<br />
*TheMonadicWay> <br />
<br />
<br />
===Monadic evaluator with output and exceptions===<br />
<br />
We will now try to combine the [[The Monadic Way Part I#MonadicEvalIO|output-producing monadic evaluator]] <br />
with [[The Monadic Way Part I#MonadicEvalE| exception producing one]].<br />
<br />
<br />
<haskell><br />
<br />
> data M2 a = Ex Exception<br />
> | Done {unpack :: (a,O) }<br />
> deriving (Show)<br />
<br />
</haskell><br />
<br />
Now we need a datatype with two constructor: one to produce a value<br />
type "M2 a" using "Ex String" and one for value type "M2 a" (Int in<br />
this case) using "Done a".<br />
<br />
'''Note''' that we changed the name of the exception type constructor<br />
from "Raise" to "Ex" just to make the two coexist in the same Literate<br />
Haskell file.<br />
<br />
The constructor "Done a" is defined with a label sector: <hask>Done {unpack :: (a,O)}</hask> <br />
and is equivalent to <hask>Done (a,O)</hask>. <br />
<br />
The only difference is that, this way, we are also defining a method<br />
to retrieve the pair (a,O) (in our case "O" is a synonymous for<br />
String, whereas "a" is a variable type) from an object of type "Done<br />
a".<br />
<br />
<haskell><br />
<br />
> instance Monad M2 where<br />
> return a = Done (a, "")<br />
> m >>= f = case m of<br />
> Ex e -> Ex e<br />
> Done (a, x) -> case (f a) of<br />
> Ex e1 -> Ex e1<br />
> Done (b, y) -> Done (b, x ++ y)<br />
<br />
</haskell><br />
<br />
Now our binding operations gets more complicated by the fact that we<br />
have to concatenate the output, as we did before, '''and''' check for<br />
exceptions.<br />
<br />
It is not possible to do has we did in the [[The Monadic Way Part I#MonadicEvalE| exception producing evaluator]], <br />
where we could check just for "m" (remember the "m" in the first run<br />
stands for "eval t").<br />
<br />
Since at the end we must return the output produced by the evaluation<br />
of "m" ''concatenated'' with the output produced by the evaluation of<br />
"f a" (where "a" is returned by "m", paired with "x" by "Done"), now<br />
we must check if we '''do have''' an output from "f a" produced by<br />
"Done".<br />
<br />
Indeed, now, "f a" can also produce a value constructed by "Ex", and<br />
this value does not contain the pair as the value produced by "Done".<br />
<br />
So, we evaluate "m": <br />
* if we match a value produced by type constructor "Ex" we return a value produced by type constructor "Ex" whose content is the one we extracted in the matching;<br />
* if we match a value produced by "Done" we match the pair it carries "(a,x)" and we analyze what "f a" returns:<br />
** if "f a" returns a value produced by "Ex" we extract the exception and we return it, constructing a value with "Ex"<br />
** if "f a" returns a value produced by "Done" we return "b" and the concatenated "x" and "y". <br />
<br />
And now the evaluator:<br />
<br />
<haskell><br />
<br />
> raise_IOE :: Exception -> M2 a<br />
> raise_IOE e = Ex e<br />
<br />
</haskell><br />
<br />
This is the function to insert in our monad (M2) an exception: we take<br />
a String and produce a value applying the type constructor for<br />
exception "Ex" to its value.<br />
<br />
<haskell><br />
<br />
> print_IOE :: O -> M2 ()<br />
> print_IOE x = Done ((), x)<br />
<br />
</haskell><br />
<br />
The function to produce output is the very same of the one of the [[The Monadic Way Part I#MonadicEvalIO|output-producing monadic evaluator]].<br />
<br />
<haskell><br />
<br />
> eval_IOE :: Term -> M2 Int<br />
> eval_IOE (Con a) = do print_IOE (formatLine (Con a) a)<br />
> return a<br />
> eval_IOE (Add t u) = do a <- eval_IOE t<br />
> b <- eval_IOE u<br />
> let out = formatLine (Add t u) (a + b)<br />
> print_IOE out<br />
> if (a+b) == 42<br />
> then raise_IOE $ out ++ "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
</haskell><br />
<br />
The evaluator procedure did not change very much from the one of the [[The Monadic Way Part I#MonadicEvalIO|output-producing monadic evaluator]].<br />
<br />
We just added the case analysis to see if the condition for raising an exception is met.<br />
<br />
Running with<br />
<br />
eval_IOE (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2)))<br />
<br />
will produce <br />
<br />
Ex "eval (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2))) <= 42 - <br />
The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
<br />
Look at the <hask>let</hask> clause within the do-notation. We do not<br />
need to use the "let ... in" construction: since all bound variables<br />
remain bound within a <hask>do</hask> procedure (see [[The Monadic Way Part I#Bind|here]]), <br />
we do not need the "in" to specify "where" the variable "out" will be bound in!<br />
<br />
==We need a state==<br />
<br />
We will keep on adding complexity to our monadic evaluator and this<br />
time we will add a counter. We just want to count the number of<br />
iterations (the number of times "eval" will be called) needed to<br />
evaluate the expression.<br />
<br />
===The basic evaluator, non monadic, with a counter===<br />
<br />
As before we will start by adding this feature to our [[The Monadic Way Part I#BasicEval|basic evaluator]]. <br />
<br />
A method to count the number of iterations, since the lack of<br />
assignment and destructive updates (such as for i=0;i<10;i++;),<br />
is to add an argument to our function, the initial state, number that<br />
in each call of the function will be increased and passed to the next<br />
function call.<br />
<br />
And so, very simply:<br />
<br />
<haskell><br />
<br />
> -- non monadic<br />
> type St a = State -> (a, State)<br />
> type State = Int<br />
> evalNMS :: Term -> St Int<br />
> evalNMS (Con a) x = (a, x + 1)<br />
> evalNMS (Add t u) x = let (a, y) = evalNMS t x in<br />
> let (b, z) = evalNMS u y in<br />
> (a + b, z +1)<br />
<br />
</haskell><br />
<br />
Now evalNMS takes two arguments: the expression of type Term and an<br />
State (which is a synonymous for Int), and will produce a pair<br />
(a,State), that is to say a pair with a variable type "a" and an Int.<br />
<br />
The operations in the evaluator are very similar to the non monadic [[The Monadic Way Part I#BasivEvalO|output producing evaluator]].<br />
<br />
We are now using the "let ... in" clause, instead of the "where", and we are increasing the counter "z" the comes from the evaluation of the second term, but the basic operation are the same:<br />
* we evaluate "evalNMS t x" where "x" is the initial state, and we match and bind the result in "let (a, y) ... in"<br />
* we evaluate "evalNMS u y", where "y" was bound to the value returned by the previous evaluation, and we match and bind the result in "let (b, z) ... in"<br />
* we return a pair formed by the sum of the result (a+b) and the state z increased by 1. <br />
<br />
Let's try it:<br />
<br />
*TheMonadicWay> evalNMS (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2))) 0<br />
(42,7)<br />
*TheMonadicWay> <br />
<br />
As you see we must pass to "evalNMS"the initial state of our counter: 0.<br />
<br />
Look at the type signature of the function "evalNMS":<br />
<haskell><br />
evalNMS :: Term -> St Int<br />
</haskell><br />
<br />
From this signature you could argue that our function takes only<br />
'''one''' argument. But since our type St is defined with the "type"<br />
keyword, St can be substituted with what comes after the "=" sign. So,<br />
the real type signature of our function is:<br />
<br />
<haskell><br />
evalNMS :: Term -> State -> (Int,State)<br />
</haskell><br />
<br />
<div if="typeNewtype"><br />
Just to refresh your memory:<br />
<br />
<haskell><br />
<br />
> type IamAfunction a = (a -> a)<br />
> newtype IamNotAfunction a = NF (a -> a)<br />
> newtype IamNotAfunctionButYouCanUnPackAndRunMe a = F { unpackAndRun :: (a -> a) }<br />
<br />
> a = \x -> x * x<br />
<br />
> a1 :: IamAfunction Integer<br />
> a1 = a<br />
<br />
> a2 :: IamNotAfunction Integer<br />
> a2 = NF a<br />
<br />
> a3 :: IamNotAfunctionButYouCanUnPackAndRunMe Integer<br />
> a3 = F a<br />
<br />
</haskell><br />
<br />
<br />
*TheMonadicWay> a 4<br />
16<br />
*TheMonadicWay> a1 4<br />
16<br />
*TheMonadicWay> a2 4<br />
<br />
<interactive>:1:0:<br />
The function `a2' is applied to one arguments,<br />
but its type `IamNotAfunction Int' has only 0<br />
In the definition of `it': it = a2 4<br />
*TheMonadicWay> a3 4<br />
<br />
<interactive>:1:0:<br />
The function `a3' is applied to one arguments,<br />
but its type `IamNotAfunctionButYouCanUnPackAndRunMe Int' has only 0<br />
In the definition of `it': it = a3 4<br />
*TheMonadicWay> unpackAndRun a3 4<br />
16<br />
*TheMonadicWay><br />
<br />
This means that "a1" is a partial application hidden by a type<br />
synonymous. <br />
<br />
"a2" and "a3" are not function types. They are types that<br />
have a functional value. <br />
<br />
Moreover, since we defined the type constructor of type<br />
"IamNotAfunctionButYouCanUnPackAndRunMe", F, with a label field, in<br />
that label field we defined a method (a label selector) to "extract"<br />
the function from the type "IamNotAfunctionButYouCanUnPackAndRunMe",<br />
and run it:<br />
<br />
<haskell><br />
unpackAndRun a3 4<br />
</haskell><br />
<br />
And what about "a2"? Is it lost forever?<br />
<br />
Obviously not! We need to write a function that unpacks a type<br />
"IamNotAfunction", using its type constructor NF to match the internal<br />
function:<br />
<br />
<haskell><br />
<br />
> unpackNF :: IamNotAfunction a -> a -> a<br />
> unpackNF (NF f) = f<br />
<br />
</haskell><br />
<br />
and run:<br />
<br />
*TheMonadicWay> unpackNF a2 4<br />
16<br />
*TheMonadicWay> <br />
<br />
As you see, "unpackNF" definition is a partial application: we specify<br />
one argument to get a function that gets another argument.<br />
<br />
A label selector does the same thing.<br />
<br />
Later we will see the importance of this distinction, quite obvious<br />
for haskell gurus, but not for us. Till now.<br />
<br />
===The evaluator, monadic, with a counter===<br />
<br />
We will now rewrite our basic evaluator with the counter in<br />
do-notation.<br />
<br />
As we have seen, in order to do so we need:<br />
* a new type that we must declare as an instance of the Monad class;<br />
* a function for binding method (>>=) and a function for the "return" method, for the instance declaration; <br />
<br />
Now our type will be holding a function that will take the initial<br />
state 0 as we did before.<br />
<br />
In order to simplify the process of unpacking the monad each time to<br />
get the function, we will use a label sector:<br />
<br />
<haskell><br />
<br />
> newtype MS a = MS { unpackMSandRun :: (State -> (a, State)) }<br />
<br />
</haskell><br />
<br />
This is it: MS will be our type constructor for matching and for<br />
building our monad. "unpackMSandRun" will be the method to get the<br />
function out of the monad to feed it with the initial state of the<br />
counter, 0, to get our result.<br />
<br />
Then we need the "return" function that, as we have seen does nothing<br />
but inserting into our monad an Integer:<br />
<br />
<haskell><br />
<br />
> mkMS :: a -> MS a<br />
> mkMS int = MS (\x -> (int, x))<br />
<br />
</haskell><br />
<br />
"mkMS" will just take an Integer "a" and apply the MS type constructor<br />
to our anonymous function that takes an initial state and produces the<br />
final state "x" and the integer "a".<br />
<br />
In other words, we are just creating our monad with inside an Integer.<br />
<br />
Our binding function will be a bit more complicated then before. We<br />
must create a type that holds an anonymous function with elements to<br />
be extracted from our type and passed to the anonymous function that<br />
comes next:<br />
<br />
<haskell><br />
<br />
> bindMS :: MS a -> (a -> MS b) -> MS b<br />
> bindMS monad doNext = MS $ \initialState -> <br />
> let (oldInt, oldState) = unpackMSandRun monad initialState in<br />
> let (newInt, newState) = unpackMSandRun (doNext oldInt) oldState in<br />
> (newInt,newState)<br />
<br />
</haskell><br />
<br />
So, we are creating an anonymous function that will take an initial<br />
state, 0, and return a "newInt" and "newState". <br />
<br />
To do that we need to unpack and run our "monad" against the<br />
initialState in order to get the "oldInt" and the "oldState".<br />
<br />
The "oldInt" will be passed to the "doNext" function (the next<br />
anonymous function in our do block) together with the "oldState" to<br />
get the "newInt" and the "newState".<br />
<br />
We can now declare our type "MS" as an instance of the Monad class:<br />
<haskell><br />
<br />
> instance Monad MS where<br />
> return a = mkMS a<br />
> (>>=) m f = bindMS m f<br />
<br />
</haskell><br />
<br />
We now need a function to increase the counter in our monad from<br />
within a do block:<br />
<br />
<haskell><br />
<br />
> incState :: MS ()<br />
> incState = MS (\s -> ((), s + 1))<br />
<br />
</haskell><br />
<br />
This is easier then it looks like. We use the type constructor MS to<br />
create a function that takes a state an returns a void integer ()<br />
paired with the state increased by one. We do not need any binding,<br />
since we are just modifying the state, an integer, and, in our do<br />
block, we will insert this function before a new line, so that the non<br />
binding ">>" operator will be applied.<br />
<br />
And now the evaluator:<br />
<br />
<haskell><br />
<br />
> evalMS :: Term -> MS Int<br />
> evalMS (Con a) = do incState<br />
> mkMS a<br />
> evalMS (Add t u) = do a <- evalMS t<br />
> b <- evalMS u<br />
> incState <br />
> return (a + b)<br />
<br />
</haskell><br />
<br />
Very easy: we just added the "incState" function before returning the<br />
sum of the evaluation of the Terms of our expression.<br />
<br />
Let's try it:<br />
<br />
*TheMonadicWay> unpackMSandRun (evalMS (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12))))) 0<br />
(54,7)<br />
*TheMonadicWay> <br />
<br />
As you can see, adding a counter makes our binding operations a bit<br />
more complicated by the fact that we have an anonymous function within<br />
our monad. This means that we must recreate that anonymous function in<br />
each step of our do block. This makes "incState" and, as we are going<br />
to see in the next paragraph, the function to produce output a bit<br />
more complicated. Anyway we can handle this complexity quite well, for<br />
now.<br />
<br />
===The monadic evaluator with output and counter in do-notation===<br />
<br />
Adding output to our evaluator is now quite easy. It's just a matter<br />
of adding a field to our type, where we are going to accumulate the<br />
output, and take care of extracting it in our bind function to<br />
concatenate the old one with the new one.<br />
<br />
<haskell><br />
<br />
> newtype Eval_SIO a = Eval_SIO { unPackMSIOandRun :: State -> (a, State, Output) }<br />
<br />
</haskell><br />
<br />
Now our monad contains an anonymous function that takes the initial<br />
state, 0, and will produce the final Integer, the final state and the<br />
concatenated output.<br />
<br />
So, this is bind:<br />
<br />
<haskell><br />
<br />
> bindMSIO monad doNext = <br />
> Eval_SIO (\initialState -><br />
> let (oldInt, oldState, oldOutput) = unPackMSIOandRun monad initialState in<br />
> let (newInt, newState, newOutput) = unPackMSIOandRun (doNext oldInt) oldState in<br />
> (newInt, newState, oldOutput ++ newOutput))<br />
<br />
</haskell><br />
<br />
And this is our "return":<br />
<haskell><br />
<br />
> mkMSIO int = Eval_SIO (\s -> (int, s, ""))<br />
<br />
</haskell><br />
<br />
Now we can declare our type, "Eval_SIO", as an instance of the Monad class:<br />
<br />
<haskell><br />
<br />
> instance Monad Eval_SIO where<br />
> return a = mkMSIO a<br />
> (>>=) m f = bindMSIO m f<br />
<br />
</haskell><br />
<br />
Now, the function to increment the counter will also insert an empty<br />
string "" in our monad: "bind" will take care of concatenating it with<br />
the old output:<br />
<br />
<haskell><br />
<br />
> incSIOstate :: Eval_SIO () <br />
> incSIOstate = Eval_SIO (\s -> ((), s + 1, ""))<br />
<br />
</haskell><br />
<br />
The function to insert some new output will just insert a string into<br />
our monad, together with a void Integer (). Since no binding will<br />
occur (>> will be applied), the () will not be taken into<br />
consideration within the anonymous functions automatically created for<br />
us within the do block:<br />
<br />
<haskell><br />
<br />
> print_SIO :: Output -> Eval_SIO ()<br />
> print_SIO x = Eval_SIO (\s -> ((),s, x))<br />
<br />
</haskell><br />
<br />
And now the evaluator, that puts everything together. As you can see<br />
it did not change too much from the previous versions:<br />
<br />
<haskell><br />
<br />
> eval_SIO :: Term -> Eval_SIO Int<br />
> eval_SIO (Con a) = do incSIOstate<br />
> print_SIO (formatLine (Con a) a)<br />
> return a<br />
> eval_SIO (Add t u) = do a <- eval_SIO t<br />
> b <- eval_SIO u<br />
> incSIOstate<br />
> print_SIO (formatLine (Add t u) (a + b))<br />
> return (a + b)<br />
<br />
</haskell><br />
<br />
Running it will require unpacking the monad and feeding it with the initial state 0:<br />
<br />
unPackMSIOandRun (eval_SIO (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12))))) 0<br />
*TheMonadicWay> unPackMSIOandRun (eval_SIO (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12))))) 0<br />
(54,7,"eval (Con 6) <= 6 - eval (Con 16) <= 16 - <br />
eval (Con 20) <= 20 - <br />
eval (Con 12) <= 12 - <br />
eval (Add (Con 20) (Con 12)) <= 32 - <br />
eval (Add (Con 16) (Add (Con 20) (Con 12))) <= 48 - <br />
eval (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <= 54 - ")<br />
*TheMonadicWay> <br />
<br />
(I formatted the output).<br />
<br />
<br />
==If there's a state we need some discipline: Dealing with complexity==<br />
<br />
'''(Text to be done yet: just a summary)'''<br />
<br />
In order to increase the complexity of our monad now we will try to<br />
mix State (counter), Exceptions and Output.<br />
<br />
This is an email [http://www.haskell.org/pipermail/haskell-cafe/2006-August/017672.html I send to the haskell-cafe mailing list]:<br />
<br />
<pre><br />
Now I'm trying to create a statefull evaluator, with output and<br />
exception, but I'm facing a problem I seem not to be able to<br />
conceptually solve.<br />
<br />
Take the code below.<br />
Now, in order to get it run (and try to debug) the Eval_SOI type has a<br />
Raise constructor that produces the same type of SOIE. Suppose instead it<br />
should be constructing something like Raise "something". <br />
Moreover, I wrote a second version of >>=, commented out.<br />
This is just to help me illustrate to problem I'm facing.<br />
<br />
Now, >>= is suppose to return Raise if "m" is matched against Raise<br />
(second version commented out).<br />
If "m" matches SOIE it must return a SOIE only if "f a" does not<br />
returns a Raise (output must be concatenated).<br />
<br />
I seem not to be able to find a way out. Moreover, I cannot understand<br />
if a way out can be possibly found. Something suggests me it could be<br />
related to that Raise "something".<br />
But my feeling is that functional programming could be something out<br />
of the reach of my mind... by the way, I teach Law, so perhaps you'll<br />
forgive me...;-)<br />
<br />
If you can help me to understand this problem all I can promise is<br />
that I'll mention your help in the tutorial I'm trying to write on<br />
"the monadic way"... that seems to lead me nowhere.<br />
<br />
Thanks for your kind attention.<br />
<br />
Andrea<br />
</pre><br />
<br />
This was the code:<br />
<br />
<haskell><br />
data Eval_SOI a = Raise { unPackMSOIandRun :: State -> (a, State, Output) }<br />
| SOIE { unPackMSOIandRun :: State -> (a, State, Output) }<br />
<br />
instance Monad Eval_SOI where<br />
return a = SOIE (\s -> (a, s, ""))<br />
m >>= f = SOIE (\x -><br />
let (a, y, s1) = unPackMSOIandRun m x in<br />
case f a of<br />
SOIE nextRun -> let (b, z, s2) = nextRun y in <br />
(b, z, s1 ++ s2)<br />
Raise e1 -> e1 y --only this happens<br />
<br />
)<br />
-- (>>=) m f = case m of<br />
-- Raise e -> error "ciao" -- why this is not going to happen?<br />
-- SOIE a -> SOIE (\x -><br />
-- let (a, y, s1) = unPackMSOIandRun m x in<br />
-- let (b, z, s2) = unPackMSOIandRun (f a) y in <br />
-- (b, z, s1 ++ s2)) <br />
<br />
<br />
incSOIstate :: Eval_SOI ()<br />
incSOIstate = SOIE (\s -> ((), s + 1, ""))<br />
<br />
print_SOI :: Output -> Eval_SOI ()<br />
print_SOI x = SOIE (\s -> ((),s, x))<br />
<br />
raise x e = Raise (\s -> (x,s,e))<br />
<br />
eval_SOI :: Term -> Eval_SOI Int<br />
eval_SOI (Con a) = do incSOIstate<br />
print_SOI (formatLine (Con a) a)<br />
return a<br />
eval_SOI (Add t u) = do a <- eval_SOI t<br />
b <- eval_SOI u<br />
incSOIstate<br />
print_SOI (formatLine (Add t u) (a + b))<br />
if (a + b) == 42 <br />
then raise (a+b) " = The Ultimate Answer!!"<br />
else return (a + b)<br />
<br />
runEval exp = case eval_SOI exp of<br />
Raise a -> a 0<br />
SOIE p -> let (result, state, output) = p 0 in<br />
(result,state,output)<br />
<br />
<br />
<br />
--runEval (Add (Con 10) (Add (Con 28) (Add (Con 40) (Con 2))))<br />
</haskell><br />
<br />
This code will produce <br />
<br />
eval (Con 10) <= 10 -<br />
eval (Con 28) <= 28 -<br />
eval (Con 40) <= 40 -<br />
eval (Con 2) <= 2 - = The Ultimate Answer!!<br />
eval (Add (Con 28) (Add (Con 40) (Con 2))) <= 70 -<br />
eval (Add (Con 10) (Add (Con 28) (Add (Con 40) (Con 2)))) <= 80 -<br />
<br />
The exception appears in the output, but executioon is not stopped.<br />
<br />
===Monadic evaluator with output, counter and exception, in do-notation===<br />
<br />
Brian Hulley [http://www.haskell.org/pipermail/haskell-cafe/2006-August/017680.html came up with this solution]:<br />
<br />
<haskell><br />
<br />
> -- thanks to Brian Hulley<br />
> data Result a<br />
> = Good a State Output<br />
> | Bad State Output Exception<br />
> deriving Show<br />
<br />
> newtype Eval_SIOE a = SIOE {runSIOE :: State -> Result a}<br />
<br />
> instance Monad Eval_SIOE where<br />
> return a = SIOE (\s -> Good a s "")<br />
> m >>= f = SIOE $ \x -><br />
> case runSIOE m x of<br />
> Good a y o1 -><br />
> case runSIOE (f a) y of<br />
> Good b z o2 -> Good b z (o1 ++ o2)<br />
> Bad z o2 e -> Bad z (o1 ++ o2) e<br />
> Bad z o2 e -> Bad z o2 e<br />
<br />
> raise_SIOE e = SIOE (\s -> Bad s "" e)<br />
<br />
> incSIOEstate :: Eval_SIOE ()<br />
> incSIOEstate = SIOE (\s -> Good () (s + 1) "")<br />
<br />
> print_SIOE :: Output -> Eval_SIOE ()<br />
> print_SIOE x = SIOE (\s -> Good () s x)<br />
<br />
<br />
> eval_SIOE :: Term -> Eval_SIOE Int<br />
> eval_SIOE (Con a) = do incSIOEstate<br />
> print_SIOE (formatLine (Con a) a)<br />
> return a<br />
> eval_SIOE (Add t u) = do a <- eval_SIOE t<br />
> b <- eval_SIOE u<br />
> incSIOEstate<br />
> let out = formatLine (Add t u) (a + b)<br />
> print_SIOE out<br />
> if (a+b) == 42<br />
> then raise_SIOE $ out ++ "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
> runEval exp = case runSIOE (eval_SIOE exp) 0 of<br />
> Bad s o e -> "Error at iteration n. " ++ show s ++ <br />
> " - Output stack = " ++ o ++ <br />
> " - Exception = " ++ e<br />
> Good a s o -> "Result = " ++ show a ++ <br />
> " - Iterations = " ++ show s ++ " - Output = " ++ o<br />
<br />
</haskell><br />
<br />
Run with runEval (Add (Con 18) (Add (Con 12) (Add (Con 10) (Con 2))))<br />
<br />
==Suggested readings==<br />
<br />
:Cale Gibbard, [[Monads as containers]]<br />
:Jeff Newbern, [http://haskell.org/all_about_monads/html/contmonad.html All About Monads]<br />
:[[IO inside]]<br />
:[http://sigfpe.blogspot.com/2006/08/you-could-have-invented-monads-and.html You Could Have Invented Monads! (And Maybe You Already Have.) by sigfpe]<br />
<br />
<br />
==Acknowledgments==<br />
<br />
Thanks to Neil Mitchell, Daniel Fisher, Bulat Ziganzhin, Brian Hulley<br />
and Udo Stenzel for the invaluable help they gave, in the<br />
[http://www.haskell.org/mailman/listinfo/haskell-cafe haskell-cafe mailing list], <br />
in understanding this topic.<br />
<br />
I couldn't do it without their help.<br />
<br />
Obviously errors are totally mine. But this is a wiki so, please,<br />
correct them!<br />
<br />
- [[User:AndreaRossato|Andrea Rossato]]<br />
<br />
[[Category:Tutorials]]<br />
[[Category:Monad]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=The_Monadic_Way_Part_I&diff=14657The Monadic Way Part I2007-07-24T22:32:40Z<p>BrettGiles: The Monadic Way Part I moved to The Monadic Way/Part I: Makes sense as a sub page - no other links to it directly.</p>
<hr />
<div>#redirect [[The Monadic Way/Part I]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=The_Monadic_Way/Part_I&diff=14655The Monadic Way/Part I2007-07-24T22:30:30Z<p>BrettGiles: Heading case, links</p>
<hr />
<div>'''Note: this is the first part of [[The Monadic Way]]'''<br />
==An evaluation of Philip Wadler's "Monads for functional programming"==<br />
<br />
This tutorial is a "translation" of Philip Wadler's [http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf "Monads for functional programming"].<br />
(avail. from [http://homepages.inf.ed.ac.uk/wadler/topics/monads.html here])<br />
<br />
I'm a Haskell newbie trying to grasp such a difficult concept as the<br />
one of Monad and monadic computation.<br />
<br />
While [http://www.cs.utah.edu/~hal/htut/ "Yet Another Haskell Tutorial"] <br />
gave me a good understanding of the type system when it<br />
comes to monads I find it almost unreadable.<br />
<br />
But I had also Wadler's paper, and started reading it. Well, just<br />
wonderful! It explains how to ''create'' a monad!<br />
<br />
So I decided to "translate it", in order to clarify to myself the<br />
topic. And I'm now sharing this traslation ('''not completed yet'')<br />
with the hope it will be useful to someone else.<br />
<br />
Moreover, that's a wiki, so please improve it. And, specifically,<br />
correct my poor English. I'm Italian, after all.<br />
<br />
'''Note: The source of this page can be used as a Literate Haskell<br />
file and can be run with ghci or hugs: so cut paste change and run (in<br />
emacs for instance) while reading it...'''<br />
<br />
==A simple evaluator==<br />
<br />
Let's start with something simple: suppose we want to implement a new<br />
programming language. We just finished with<br />
[http://swiss.csail.mit.edu/classes/6.001/abelson-sussman-lectures/ Abelson and Sussman's Structure and Interpretation of Computer Programs] <br />
and we want to test what we have learned.<br />
<br />
Our programming language will be very simple: it will just compute the<br />
sum of two terms.<br />
<br />
So we have just one primitive operation (Add) that takes two constants<br />
and calculates their sum.<br />
<br />
Moreover we have just one kind of data type: Con a, which is an Int.<br />
<br />
For instance, something like:<br />
<br />
(Add (Con 5) (Con 6))<br />
<br />
should yield:<br />
<br />
11<br />
<br />
===The basic evaluator===<br />
<br />
We will implement our language with the help of a data type<br />
constructor such as:<br />
<br />
<div id="BasicEval"><br />
<haskell><br />
<br />
> module TheMonadicWay where<br />
> data Term = Con Int<br />
> | Add Term Term<br />
> deriving (Show)<br />
<br />
</haskell><br />
<br />
After that we build our interpreter:<br />
<br />
<haskell><br />
<br />
> eval :: Term -> Int<br />
> eval (Con a) = a<br />
> eval (Add a b) = eval a + eval b<br />
<br />
</haskell><br />
<br />
That's it. Just an example:<br />
<br />
*TheMonadicWay> eval (Add (Con 5) (Con 6))<br />
11<br />
*TheMonadicWay><br />
<br />
Very very simple. The evaluator checks if its argument is of type Con<br />
Int: if it is it just returns the Int.<br />
<br />
If the argument is not of type Con, but it is of type Term, it<br />
evaluates the first Term and sums the result with the result of the<br />
evaluation of the second Term.<br />
<br />
As you may understand, our evaluator uses some of the powerful<br />
features of Haskell type system. Instead of writing a parser that<br />
takes a string (the user input) and transforms that string into an<br />
expression to be evaluated, we use the two type constructors defined<br />
for our data type Term (Con and Add) to build the expression - such as<br />
(Add (Con 5) (Con 6)) - and to match the expression's elements in our<br />
"eval" function.<br />
<br />
<br />
== Some output, please!==<br />
<br />
Now, that's fine, but we'd like to add some features, like providing<br />
some output, to show how the computation was carried out.<br />
<br />
Well, but Haskell is a pure functional language, with no side effects,<br />
we were told.<br />
<br />
Now we seem to be wanting to create a side effect of the computation,<br />
its output, and be able to stare at it...<br />
<br />
If we had some global variable to store the out that would be<br />
simple...<br />
<br />
But we can create the output and carry it along the computation,<br />
concatenating it with the old one, and present it at the end of the<br />
evaluation together with the evaluation of the expression given to our<br />
evaluator/interpreter!<br />
<br />
===The basic evaluator with output===<br />
<br />
Simple and neat:<br />
<div id="BasivEvalO"><br />
<haskell><br />
<br />
> type MOut a = (a, Output)<br />
> type Output = String<br />
> <br />
> formatLine :: Term -> Int -> Output<br />
> formatLine t a = "eval (" ++ show t ++ ") <= " ++ show a ++ " - " <br />
> <br />
> evalO :: Term -> MOut Int<br />
> evalO (Con a) = (a, formatLine (Con a) a)<br />
> evalO (Add t u) = ((a + b),(x ++ y ++ formatLine (Add t u) (a + b)))<br />
> where (a, x) = evalO t<br />
> (b, y) = evalO u<br />
<br />
</haskell><br />
<br />
Now we have what we want. But we had to change our evaluator quite a<br />
bit. <br />
<br />
First we added a function, formatLine, that takes an argument of type<br />
Term (the expression to be evaluated), one of type Int (the result of<br />
the evaluation of Term) and gives back an output of type Output (that<br />
is a synonymous of String). This is just a helper function to format<br />
the string to output. Not very interesting at all.<br />
<br />
The evaluator itself changed quite a lot! Now it has a different type<br />
signature: it takes an argument of type Term and produces a new type,<br />
we called it MOut, that is actually a compound pair of a variable type<br />
a (an Int in our evaluator) and a type Output, a string.<br />
<br />
So our evaluator, now, will take a Term (the type of the expressions<br />
in our new programming language) and will produce a pair, composed of<br />
the result of the evaluation (an Int) and the Output, a string.<br />
<br />
So far so good. But what's happening inside the evaluator?<br />
<br />
The first part will just return a pair with the number evaluated ("a")<br />
and the output formatted by formatLine.<br />
<br />
The second part does something more complicated: it returns a pair<br />
composed by <br />
1. the result of the evaluation of the right Term summed to the result<br />
of the evaluation of the second Term<br />
2. the output: the concatenation of the output produced by the<br />
evaluation of the right Term, the output produced by the evaluation of<br />
the left Term (each this evaluation returns a pair with the number and<br />
the output), and the formatted output of the evaluation.<br />
<br />
Let's try it:<br />
*TheMonadicWay> evalO (Add (Con 5) (Con 6))<br />
(11,"eval (Con 5) <= 5 - eval (Con 6) <= 6 - eval (Add (Con 5) (Con 6)) <= 11 - ")<br />
*TheMonadicWay><br />
<br />
It works! Let's put the output this way:<br />
eval (Con 5) <= 5 - <br />
eval (Con 6) <= 6 - <br />
eval (Add (Con 5) (Con 6)) <= 11 -<br />
<br />
Great! We are able to produce a side effect of our evaluation and<br />
present it at the end of the computation, after all.<br />
<br />
Let's have a closer look at this expression:<br />
<haskell><br />
<br />
evalO (Add t u) = ((a + b),(x ++ y ++ formatLine (Add t u) (a + b)))<br />
where (a, x) = evalO t<br />
(b, y) = evalO u<br />
<br />
</haskell><br />
<br />
Why all that? The problem is that we need:<br />
* "a" and "b" to calculate their sum (a + b), that will be the first element of the compund pair rapresenting the type (MOut) our evaluator will return <br />
* "x and "y" (the output of each evaluation) to be concatenated with the ourput of formatLine by the expression (x ++ y ++ formatLine(...)): this will be the second element of the compound pair MOut, the string part.<br />
<br />
So we need to separate the pairs produced by "evalO t" and "evalO u".<br />
<br />
We do that within the where clause (remember: evalO now produces a value of type<br />
MOut Int, i.e. a pair of an Int and a String).<br />
<br />
Then we use the single element, "extraded" within the where clause, to<br />
return a new MOut composed by <br />
<br />
((a + b),(x ++ y ++ formatLine (Add t u) (a + b))).<br />
------ -------------------------------------<br />
Int Output = String<br />
<br />
== Let's go monadic==<br />
<br />
Is there a more general way of doing so?<br />
<br />
Let's analyze the evaluator from another perspective. From the type<br />
perspective.<br />
<br />
We solved our problem by creating a new type, a pair of an Int (the<br />
result of the evaluation) and a String (the output of the process of<br />
evaluation).<br />
<br />
The first part of the evaluator does nothing else but creating, from a<br />
value of type Int, an object of type MOut Int (Int,Output). It does so<br />
by creating a pair with that Int and some text produced by formatLine.<br />
<br />
The second part evaluates the two Term(s) and "stores" the values thus<br />
produced in some variables to be use later to compute the output.<br />
<br />
Let's focus on the "stores" action. The correct term should be<br />
"binds".<br />
<br />
Take a function:<br />
<haskell><br />
f x = x + x<br />
</haskell><br />
"x" appears on both sides of the expression. We say that on the right<br />
side "x" is bound to the value of x given on the left side.<br />
<br />
So<br />
<haskell><br />
f 3<br />
</haskell><br />
binds x to 3 for the evaluation of the expression "x + x".<br />
<br />
Our evaluator binds "a" and "x" / "b" and "y" with the evaluation of<br />
"evalO t" and "evalO u" respectively. <br />
<br />
Then "a","b","x" and "y" will be used in the evaluation of<br />
((a+b),(x++y++formatLine)), that will produce a value of type MOut Int:<br />
<br />
<pre><br />
<br />
((a + b),(x ++ y ++ formatLine (Add t u) (a + b))).<br />
------ -------------------------------------<br />
\ / \ /<br />
Int Output = String<br />
---------------------------------<br />
\ /<br />
MOut Int <br />
</pre><br />
<br />
The binding happens in the "where" clause:<br />
<haskell><br />
where (a, x) = evalO t<br />
(b, y) = evalO u<br />
</haskell><br />
<br />
We know that there is an ad hoc operator for binding variables to a<br />
value: lambda, or \.<br />
<br />
Indeed f x = x + x is syntactic sugar for:<br />
<haskell><br />
f = \x -> x + x<br />
</haskell><br />
When we write f 3 we are actually binding "x" to 3 within what's next<br />
"->", that will be used (substituted) for evaluating f 3.<br />
<br />
So we can try to abstract this phenomenon.<br />
<br />
===Monadic evaluator with output===<br />
What we need is a function that takes our composed type MOut Int and a<br />
function in order to produce a new MOut Int, concatenating the<br />
output of the computation of the first with the output of the<br />
computation of the second.<br />
<br />
This is what bindM does:<br />
<br />
<haskell><br />
<br />
> bindM :: MOut a -> (a -> MOut b) -> MOut b<br />
> bindM m f = (b, x ++ y)<br />
> where (a, x) = m<br />
> (b, y) = f a<br />
<br />
</haskell><br />
<br />
It takes:<br />
* "m": the compound type MOut Int carrying the result of an "eval Term",<br />
* a function "f". This function will take the Int ("a") extracted by the evaluation of "m" ((a,x)=m). This function will produce a new pair: a new Int produced by a new evaluation; some new output.<br />
<br />
bindM will return the new Int in pair with the concatenated outputs<br />
resulting from the evaluation of "m" and "f a".<br />
<br />
As you see, we took the binding part out from evalO and put it in this new function.<br />
<br />
So let's write the new version of the evaluator, that we will call evalM_1:<br />
<br />
<haskell><br />
<br />
> evalM_1 :: Term -> MOut Int<br />
> evalM_1 (Con a) = (a, formatLine (Con a) a)<br />
> evalM_1 (Add t u) = bindM (evalM_1 t) (\a -> <br />
> bindM (evalM_1 u) (\b -> <br />
> ((a + b), formatLine (Add t u) (a + b))<br />
> )<br />
> )<br />
<br />
</haskell><br />
<br />
Ugly, isn't it?<br />
<br />
Let's start from the outside:<br />
<br />
<haskell><br />
bindM (evalM_1 u) (\b -> ((a + b), formatLine (Add t u) (a + b)))<br />
</haskell><br />
<br />
bindM takes the result of the evaluation "evalM_1 u", a type Mout Int,<br />
and a function. It will extract the Int from that type and use it to<br />
bind "b".<br />
<br />
So in bindM (evalM_1 u) (\b ->) "b" will be bound to the value<br />
returned by evalM_1 u, and this bound variable will be available in<br />
what comes after "->" as a bound variable (not free).<br />
<br />
Then the outer part (bindM (evalM_1 t) (\a...) will bind "a" to the<br />
value returned "evalM_1 t", the result of the evaluatuion of the first<br />
Term. This value is needed to evaluate "((a+b), formatLine...) and<br />
produce our final MOut Int.<br />
<br />
We can try to explain "bindM" in a different way by using more descriptive names.<br />
<br />
As we have seen, "bindM" extracts the Int part from our type. The Int<br />
part will be used for further computations and the Output part will be<br />
concatenated. As a result we will have a new pair with a new Int and<br />
an accumulated Output.<br />
<br />
The new version of "bindM":<br />
<haskell><br />
<br />
> getIntFromType typeMOut doSomething = (newInt,oldOutput ++ newOutput)<br />
> where (oldInt,oldOutput) = typeMOut<br />
> (newInt,newOutput) = (doSomething oldInt)<br />
<br />
</haskell><br />
<br />
As you can see it does the very same things that "bindM" does: it<br />
takes something of type MOut and a function to perform some<br />
computation with the Int part. <br />
<br />
In the "where" clause, the old Int and the old output<br />
will be extracted from our type MOut (first line of the "where"<br />
clause). <br />
<br />
A new Int and a new output will be extracted from evaluating<br />
(doSomething oldInt) in the second line.<br />
<br />
Our function will return the new Int and the concatenated outputs.<br />
<br />
We do not need to define our doSomething function, because it will be<br />
an anonymous function:<br />
<br />
<haskell><br />
<br />
> evaluator (Con a) = (a, "output-")<br />
> evaluator (Add t u) = <br />
> getIntFromType (evaluator t) <br />
> (\firstInt -> getIntFromType (evaluator u) <br />
> (\secondInt -> ((firstInt + secondInt),("-newoutput"))))<br />
<br />
</haskell><br />
<br />
As you can see we are feeding our "getIntFromType" with the evaluation<br />
of an expression ("evaluator t" and "evaluator u"). The second<br />
argument of "getIntFromType" is an anonymous function that takes the<br />
"oldInt" and does something with it.<br />
<br />
So we have a series of nested anonymous functions. Their arguments<br />
("\firstInt" and "\secondInt") will be used to produce the computation<br />
we need ("(firstInt + secondInt). Moreover "getIntFromType" will take<br />
care of concatenating the outputs.<br />
<br />
This is the result:<br />
<br />
*TheMonadicWay> evaluator (Add (Con 5) (Con 6))<br />
(11,"output-output--newoutput")<br />
*TheMonadicWay> <br />
<br />
Going back to our "bindM", we can now use lambda notation to write our<br />
evaluator in a more convinient way:<br />
<br />
<haskell><br />
<br />
> evalM_2 :: Term -> MOut Int<br />
> evalM_2 (Con a) = (a, formatLine (Con a) a)<br />
> evalM_2 (Add t u) = evalM_2 t `bindM` \a -><br />
> evalM_2 u `bindM` \b -><br />
> ((a + b), (formatLine (Add t u) (a + b)))<br />
<br />
</haskell><br />
<br />
Now, look at the first part:<br />
<br />
<haskell><br />
evalM_2 (Con a) = (a, formatLine (Con a) a)<br />
</haskell><br />
<br />
We could use a more general way of creating some output. <br />
<br />
We can create a function that takes an Int and returns the type MOut<br />
Int. We do that by pairing the received Int with an empty string "".<br />
<br />
This will be a general way of creating an object with type MOut Int starting from an Int.<br />
<br />
Or, more generaly, a function that takes something of a variable type<br />
a, and return an object of type MOut a, a coumpunt object made up of<br />
an element of type a, and one of type String.<br />
<br />
There it is:<br />
<br />
<haskell><br />
<br />
> mkM :: a -> MOut a<br />
> mkM a = (a, "")<br />
<br />
</haskell><br />
<br />
As you can see, this function will just push an Int and an empty<br />
string ("") inside our type MOut.<br />
<br />
Then we need a method of inserting some text in our object of type<br />
MOut. So we will take a string and return it paired with a void<br />
element "()":<br />
<br />
<haskell><br />
<br />
> outPut :: Output -> MOut ()<br />
> outPut x = ((), x)<br />
<br />
</haskell><br />
<br />
Very simple: we have a string "x" (Output) and create a pair with a ()<br />
instead of an Int, and the output.<br />
<br />
You can see this function as one that pushes a string, paired with a<br />
void int, inside our type MOut.<br />
<br />
Now we can rewrite:<br />
<haskell><br />
evalM_2 (Con a) = (a, formatLine (Con a) a)<br />
</haskell><br />
using the bindM function:<br />
<haskell><br />
evalM_2 (Con a) = outPut (formatLine (Con a) a) `bindM` \_ -> mkM a<br />
</haskell><br />
<br />
First we create an object of type MOut with the Int part (). As you<br />
see bindM will not use it ("\_"), but will concatenate the String part<br />
with the result of mkM, which in turn is the empty string "".<br />
<br />
In other words, first we insert the Output part (a string) in our<br />
MOut, and then we insert the Int paired with an empty string: "bindM"<br />
will not use the void int (the anonymous function will not use it's<br />
argument: "\_"), but will take care of concatenating the non empty<br />
string inserted by "outPut" with the empty one inserted by "mkM".<br />
<br />
Let's rewrite the evaluator:<br />
<br />
<haskell><br />
<br />
> evalM_3 :: Term -> MOut Int<br />
> evalM_3 (Con a) = outPut (formatLine (Con a) a) `bindM` \_ -> <br />
> mkM a<br />
> evalM_3 (Add t u) = evalM_3 t `bindM` \a -><br />
> evalM_3 u `bindM` \b -><br />
> outPut (formatLine (Add t u) (a + b)) `bindM` \_ -> <br />
> mkM (a + b)<br />
<br />
</haskell><br />
<br />
Well, this is fine, definetly better then before, anyway.<br />
<br />
Still we use `bindM` \_ -> that binds something we do not use (_). We<br />
could write a function for this specific case, when we concatenate<br />
computations without the need of binding variables for later uses.<br />
Let's call it `combineM`:<br />
<br />
<haskell><br />
<br />
> combineM :: MOut a -> MOut b -> MOut b<br />
> combineM m f = m `bindM` \_ -> f<br />
<br />
</haskell><br />
<br />
This is just something that will allow us to write the evaluator in a<br />
more concise way. <br />
<br />
So the new evaluator:<br />
<br />
<haskell><br />
<br />
> evalM :: Term -> MOut Int<br />
> evalM (Con a) = outPut (formatLine (Con a) a) `combineM` <br />
> mkM a<br />
> evalM (Add t u) = evalM t `bindM` \a -><br />
> evalM u `bindM` \b -><br />
> outPut (formatLine (Add t u) (a + b)) `combineM` <br />
> mkM (a + b)<br />
<br />
</haskell><br />
<br />
Let's put everything together (changing M into MO, so that this file<br />
will be still usable as a Literate Haskell file):<br />
<br />
<haskell><br />
<br />
> type MO a = (a, Out)<br />
> type Out = String<br />
<br />
> mkMO :: a -> MO a<br />
> mkMO a = (a, "")<br />
<br />
> bindMO :: MO a -> (a -> MO b) -> MO b<br />
> bindMO m f = (b, x ++ y)<br />
> where (a, x) = m<br />
> (b, y) = f a<br />
<br />
> combineMO :: MO a -> MO b -> MO b<br />
> combineMO m f = m `bindM` \_ -> f<br />
<br />
> outMO :: Out -> MO ()<br />
> outMO x = ((), x)<br />
<br />
> evalMO :: Term -> MO Int<br />
> evalMO (Con a) = outMO (formatLine (Con a) a) `combineMO`<br />
> mkMO a<br />
> evalMO (Add t u) = evalMO t `bindMO` \a -><br />
> evalMO u `bindMO` \b -><br />
> outMO (formatLine (Add t u) (a + b)) `combineMO` <br />
> mkMO (a + b)<br />
<br />
</haskell><br />
<br />
==What does bind bind?==<br />
<br />
<div id="Bind"><br />
The evaluator looks like:<br />
<haskell><br />
evalM t >>= \a -> evalM u >>= \b -> outPut "something" >>= \_ -> mkM (a +b)<br />
</haskell><br />
where >>= is bindMO, obviously.<br />
<br />
Let's do some substitution, writing the type of their output of each function:<br />
* evalMO t => (a,Out) - where a is Int<br />
* evalMO u => (b,Out) - where b is the same of a, an Int, but with a different value<br />
* outMO Out = ((),Out)<br />
* mkMO (a+b) => ((a+b),Out) - where (a+b) is the same of a and b, but with a different value from either a and b<br />
<br />
<pre><br />
B | (a,Out) >>= \a -> (b,Out) >>= \b -> ((),Out) >>= \_ >>= ((a + b), Out)---\<br />
i | V V V V V V V V ^ ^ ^ ^ |\<br />
n | |__|________^ | | ^ | | | | | | | MOut Int <=> ((a+b), Out)<br />
d |_____|__(++)__|_Out_|__|__(++)__V_Out_|___|___(++)_|_(++)__|___|____|_____|/<br />
i | | |______(b)__|_____|_____(b)____|__(b)__|___|<br />
n | |_________(a)___________|____________|__(a)__|<br />
g | |_____()_____|<br />
<br />
</pre><br />
<br />
Clear, isn't it?<br />
<br />
"bindMO" is just a function that takes care of gluing together, inside<br />
a data type, a sequence of computations!<br />
<br />
== Some sugar, please!==<br />
Now our evaluator has been completely transformed into a monadic<br />
evaluator. That's what it is: a monad.<br />
<br />
We have a function that constructs an object of type MO Int, formed by<br />
a pair: the result of the evaluation and the accumulated<br />
(concatenated) output.<br />
<br />
The process of accumulation and the act of parting the MO Int into its<br />
component is buried into bindMO, now, that can also preserve some<br />
value for later uses.<br />
<br />
So we have:<br />
* MO a type constructor for a type carrying a pair composed by an Int and a String;<br />
* bindMO, that gives a direction to the process of evaluation: it concatenates computations and captures some side effects we created (the direction is given by the changes in the Out part: there's a "before" when Out was something and there's a "later" when Out is something else).<br />
* mkMO lets us create an object of type MO Int starting from an Int.<br />
<br />
As you see this is all we need to create a monad. In other words<br />
monads arise from the type system and the lambda calculus. Everything<br />
else is just syntactic sugar.<br />
<br />
So, let's have a look at that sugar: the famous do-notation!<br />
<br />
===Monadic evaluator with output in do-notation===<br />
<br />
In order to be able to use the "do-notation" we need to define a new<br />
type and make it an instance of the Monad class. To make a new type an<br />
instance of the Monad class we will have to define the two methods of<br />
this class: (>>=) and "return".<br />
<br />
This is not going to be difficult, because we already created these<br />
two methods: "bindM" and "mkM". Now we will have to rewrite them in<br />
order to reflect the fact that we are not going to use a type, for our<br />
evaluator, that is a synonymous of other types, as we did before.<br />
Indeed our MOut was defined with the "type" keyword. Now we will have<br />
to define a "real" new type with either "newtype" or "data". Since we<br />
are not going to need multiple constructors, we will use "newtype".<br />
<br />
<div id="MonadicEvalIO"><br />
<haskell><br />
<br />
> newtype Eval_IO a = Eval_IO (a, O)<br />
> deriving (Show)<br />
> type O = String<br />
<br />
</haskell><br />
<br />
This is our new type: it will have a single type constructor, whose<br />
name is the same of the type name ("Eval_IO"). The type constructor<br />
takes a parameter ("a"), a variable type, and will build a type formed<br />
by a type "a" (an Int in our case) and a String (O is indeed<br />
synonymous of String).<br />
<br />
We now need to define our "bind" function to reflect the fact that we<br />
are now using a "real" type, and, to unpack its content, we need to do<br />
pattern-matching we the type constructor "Eval_IO". Moreover, since we<br />
must return an Eval_IO type, we will use the type constructor also for<br />
building the new type with the new int and the concatenated output.<br />
<br />
For the rest our "bind" function will be identical to the one we<br />
defined before.<br />
<br />
We are going to use very descriptive names:<br />
<br />
<haskell><br />
<br />
> getInt monad doSomething = Eval_IO (newInt,oldOutput ++ newOutput)<br />
> where Eval_IO (oldInt,oldOutput) = monad<br />
> Eval_IO (newInt,newOutput) = (doSomething oldInt)<br />
<br />
</haskell><br />
<br />
As you can see, we are using Eval_IO to build the result of the<br />
computation to be returned by getInt: "Eval_IO (newInt,oldOutput ++<br />
newOutput)". And we are using it to match the internal components of<br />
our type in the "where" clause.<br />
<br />
We also need to create a function that, like mkO, will take an Int and,<br />
using the type constructor "Eval_IO", will create an object of type<br />
Eval_IO with that Int and an empty string:<br />
<br />
<haskell><br />
<br />
> createEval_IO :: a -> Eval_IO a<br />
> createEval_IO int = Eval_IO (int,"")<br />
<br />
</haskell><br />
<br />
And, finally, we need a function that will insert, in our type, a<br />
string and a void ():<br />
<br />
<haskell><br />
<br />
> print_IO :: O -> Eval_IO ()<br />
> print_IO string = Eval_IO ((), string)<br />
<br />
</haskell> <br />
<br />
With these functions we could write our monadic evaluator without the<br />
"do-notation" like this:<br />
<br />
<haskell><br />
<br />
> evalM_4 :: Term -> Eval_IO Int<br />
> evalM_4 (Con a) = createEval_IO a<br />
> evalM_4 (Add t u) = evalM_4 t `getInt` \a -><br />
> evalM_4 u `getInt` \b -><br />
> print_IO (formatLine (Add t u) (a + b)) `getInt` \_ -><br />
> createEval_IO (a + b)<br />
<br />
</haskell><br />
<br />
It is very similar to the previous evaluator, as you can see. The only<br />
differences are related to the fact that we are now using a "real"<br />
type and not a type synonymous: this requires the use of the type<br />
constructor to match the type and its internal part (as we do in the<br />
"where" clause of our "bind" function: "getInt") or to build the type<br />
(as we do in the "bind" function to return the new Int with the<br />
concatenated output).<br />
<br />
Running this evaluator will produce:<br />
<br />
*TheMonadicWay> evalM_4 (Add (Con 6) (Con 12))<br />
Eval_IO (18,"eval (Add (Con 6) (Con 12)) <= 18 - ")<br />
*TheMonadicWay> <br />
<br />
Now we have everything we need to declare our type, Eval_IO, as an<br />
instance of the Monad class:<br />
<haskell><br />
<br />
> instance Monad Eval_IO where<br />
> return a = createEval_IO a<br />
> (>>=) m f = getInt m f<br />
<br />
</haskell><br />
<br />
As you see we are just using our defined functions as methods for our<br />
instance of the Monad class.<br />
<br />
This is all we need to do. Notice that we do not have to define the<br />
"combineM" function, for chaining computation, as we do with "getInt",<br />
without binding variables for later use within the series of nested<br />
anonymous functions (the "doSomething" part) that will form the "do"<br />
block.<br />
<br />
This function comes for free by just defining our type as an instance<br />
of the Monad class. Indeed, if you look at the definition of the Monad<br />
class in the Prelude you see that "combineM", or (>>) is deduced by<br />
the definition of (>>=):<br />
<br />
<haskell><br />
class Monad m where<br />
return :: a -> m a<br />
(>>=) :: m a -> (a -> m b) -> m b<br />
(>>) :: m a -> m b -> m b<br />
fail :: String -> m a<br />
<br />
-- Minimal complete definition: (>>=), return<br />
p >> q = p >>= \ _ -> q<br />
fail s = error s<br />
</haskell><br />
<br />
You can see that the "combineM"" method (or (>>)) is automatically<br />
derived by the "bindMO" (or >>=) method:<br />
<br />
<haskell><br />
p >> q = p >>= \ _ -> q<br />
</haskell><br />
<br />
We can now write our evaluator using the do-notation:<br />
<br />
<haskell><br />
<br />
> eval_IO :: Term -> Eval_IO Int<br />
> eval_IO (Con a) = do print_IO (formatLine (Con a) a)<br />
> return a<br />
> eval_IO (Add t u) = do a <- eval_IO t<br />
> b <- eval_IO u<br />
> print_IO (formatLine (Add t u) (a + b))<br />
> return (a + b)<br />
<br />
</haskell><br />
<br />
As you can see the anonymous functions are gone. Instead we use this:<br />
a <- eval_IO t<br />
<br />
This seems like an assignment, that cannot be possible in Haskell. In<br />
fact it is just the way our anonymous function's arguments is bound<br />
within a do block.<br />
<br />
Even if it does not seem like a series of nested anonymous functions,<br />
this is what actually a do block is.<br />
<br />
Our monad is defined by three elements: <br />
* a type, with its type constructor(s);<br />
* a bind method: it will bind an unwritten anonymous function's argument to the value of the Int part of our type, or more generally, of the variable type "a". It will also create a series of anonymous functions: a line for each function;<br />
* a "return" function, to insert, into out type, a value of type Int, or, more generally, a value of variable type "a".<br />
<br />
Additionally, we need a function to insert a string in our type,<br />
string that the derived "bind" (>>) will concatenate ignoring the void<br />
(), our "print_IO".<br />
<br />
Within a do block we can thus perform only tree kinds of operations:<br />
* a computation that produces a new Int, packed inside our monad's type, to be extracted and bound to a variable (an anonymous function's argument really):<br />
** this operation requires a binding (">>= \varName ->"), translated into "varName <- computation"<br />
** example: a <- eval_IO t<br />
* a computation that inserts a string into our monad, a string to be concatenated, without the need of binding a variable (an anonymous function's argument really):<br />
** this operation does not require a binding: it will be ">>= \_ ->", i.e. ">>", translated into a simple new line<br />
** example: print_IO (formatLine (Add t u) (a + b))<br />
* a computation that inserts an Int into our monad without the need of binding a variable (an anonymous function's argument really):<br />
** this operation is carried out by the <hask>return</hask> method (usually at the end of a do block, useless in the middle)<br />
** example <hask>return (a + b)</hask><br />
<br />
To sum up, within a block, "do" will take care of creating and<br />
nesting, for us, all the needed anonymous functions so that bound<br />
variables will be available for later computations.<br />
<br />
In this way we can emulate a direction of our computation, a "before"<br />
and an "after", even within a pure functional language. And we can use<br />
this possibility to create and accumulate side effects, like output.<br />
<br />
Let's see the evaluator with output in action:<br />
*TheMonadicWay> eval_IO (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <br />
Eval_IO (54,"eval (Con 6) <= 6 - eval (Con 16) <= 16 - eval (Con 20) <= 20 - eval (Con 12) <= 12 - \<br />
eval (Add (Con 20) (Con 12)) <= 32 - eval (Add (Con 16) (Add (Con 20) (Con 12))) <= 48 - \<br />
eval (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <= 54 - ")<br />
*TheMonadicWay> <br />
<br />
Let's format the output part:<br />
eval (Con 6) <= 6 <br />
eval (Con 16) <= 16 <br />
eval (Con 20) <= 20 <br />
eval (Con 12) <= 12 <br />
eval (Add (Con 20) (Con 12)) <= 32 <br />
eval (Add (Con 16) (Add (Con 20) (Con 12))) <= 48 <br />
eval (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <= 54 <br />
<br />
==[[Type]] and [[Newtype]]: What happened to our output?==<br />
<br />
Well, actually something happened to the output. Let's compare the<br />
output of evalMO (the monadic evaluator written without the<br />
do-notation) and eval_IO:<br />
<br />
*TheMonadicWay> evalMO (Con 6)<br />
(6,"eval (Con 6) <= 6 - ")<br />
*TheMonadicWay> eval_IO (Con 6)<br />
Eval_IO (6,"eval (Con 6) <= 6 - ")<br />
*TheMonadicWay> <br />
<br />
They look almost the same, but they are not the same: the output of<br />
eval_IO has the Eval_IO stuff. It must be related to the changes we<br />
had to do to our evaluator in order to use the do-conation, obviously.<br />
<br />
We can now review some of our basic knowledge of Haskell's type<br />
system.<br />
<br />
What's changed? First the type definition. We have now:<br />
<br />
<haskell><br />
newtype Eval_IO a = Eval_IO (a, O)<br />
deriving (Show)<br />
</haskell><br />
<br />
instead of <br />
<br />
<haskell><br />
type MO a = (a, Out)<br />
</haskell><br />
<br />
Now <hask>return a</hask> is the product of the application of the<br />
type constructor Eval_IO to the pair that are going to form our monad.<br />
<br />
"return" takes an Int and inserts it into our monad. It will also<br />
insert an empty String "" that (>>=) or (>>) will then concatenate in<br />
the sequence of computations they glue together.<br />
<br />
The same for (>>=). It will now return something constructed by<br />
Eval_IO: <br />
<br />
* "newInt", the result of the application of "doSomething" to "oldInt" (better, the binding of "oldInt" in "doSomething");<br />
* the concatenation of "oldOutput" (matched by <hask>Eval_IO (oldInt, oldOutput)</hask> with the evaluation of "monad" - "eval_IO t") and "newOutput", (matched by "Eval_IO(newInt,newOutput)" with the evaluation of "(doSomething monad)" - "eval_IO u").<br />
<br />
That is to say: in the "where" clause, we are matching for the<br />
elements paired in a type Eval_IO: this is indeed the type of "monad"<br />
(corresponding to "eval_IO t" in the body of the evaluator) and<br />
"(doSomething monad)" (where "doSomething" correspond to the<br />
evaluation of "eval_IO u" within an anonymous function with \oldInt as<br />
its argument, argument bound to the result of the previous evaluation<br />
of "monad", that is to say "eval_IO t").<br />
<br />
And so, "Eval_IO (oldInt,oldOutput) = monad" means: match "oldInt" and<br />
"oldOutput", paired in a type Eval_IO, and that are produced by the<br />
evaluation of "monad" (that is to say: "eval_IO t"). The same for<br />
Eval_IO (newInt,newOutput): match "newInt" and "newOutput" produced by<br />
the evaluation of "(doSomething monad)".<br />
<br />
So the output of the evaluator is now not simply a pair made of and<br />
Int and a String. It is a specific type (Eval_IO) that happens to<br />
carry a pair of an Int and a String. But, if we want the Int and the<br />
string, we have to extract them from the Eval_IO type, as we do in the<br />
"where" clause: we ''unpack'' our type object (let's call it with its<br />
name: our monad!) and take out the Int and the String to feed the next<br />
function application and the output generation.<br />
<br />
The same to insert something in our monad: if we want to create a pair<br />
of an Int and a String, pair of type Eval_IO, we now have to ''pack''<br />
them together by using our type constructor, feeding it with a pair<br />
composed by and Int and a String. This is what we do with the "return"<br />
method of out monad and with "print_IO" function, where:<br />
* return insert into the monad an Int;<br />
* print_IO insert into the monad a String.<br />
<br />
So, why cannot we use the old <hask>type MO a = (a, Out)</hask> that<br />
did not required all this additional work (apart the need to<br />
specifically define (>>)?<br />
<br />
Type MO is just a synonymous for (a,Out): the two can be substituted<br />
one for the other. That's it.<br />
<br />
We did not have to pack "a" and "Out" together with a type constructor<br />
to have a new type MO.<br />
<br />
As a consequence, we cannot use MO as an instance of Monad, and so, we<br />
cannot use with it the syntactic sugar we needed: the do-notation.<br />
<br />
That is to say: a type created with the "type" keyword cannot be an<br />
instance of a class, and cannot inherits its methods (in our case<br />
(>>=, >> and return). And without those methods the do-notation is not<br />
usable.<br />
<br />
==Errare monadicum est==<br />
<br />
Now that we have a basic understanding of what a monad is, and does,<br />
we will further explore it by making some changes to our evaluator.<br />
<br />
In this section we will se how to handle exceptions in our monadic<br />
evaluator.<br />
<br />
Suppose that we want to stop the execution of our monad if some<br />
conditions occurs. If our evaluator was to compute divisions, instead<br />
of sums, then we would like to stop the evaluator when a division by<br />
zero occurs, possibly producing some output, instead of the result of<br />
the evaluation of the expression, that explains what happened.<br />
<br />
Basic error handling.<br />
<br />
We will do so starting from the beginning once again...<br />
<br />
===The basic evaluator, non monadic, with exception===<br />
<br />
We just take our basic evaluator, without any output, and write a<br />
method to stop execution if a condition occurs: <br />
<br />
<haskell><br />
<br />
> data M a = Raise Exception<br />
> | Return a<br />
> deriving (Show)<br />
> type Exception = String<br />
<br />
</haskell><br />
<br />
Now, our monad is of datatype "M a" which can either be constructed<br />
with the "Raise" constructor, that takes a String (Exception is a<br />
synonymous of String), or by the "Return" constructor, that takes a<br />
variable type ("a"), an Int in our case.<br />
<br />
<haskell><br />
<br />
> evalE :: Term -> M Int<br />
> evalE (Con a) = Return a<br />
<br />
</haskell><br />
<br />
If evalE matches a Con it will construct a type Return with, inside, the content of the Con.<br />
<br />
<haskell><br />
<br />
> evalE (Add a b) = <br />
> case evalE a of<br />
> Raise e -> Raise e<br />
> Return a -><br />
> case evalE b of <br />
> Raise e -> Raise e<br />
> Return b -><br />
> if (a+b) == 42<br />
> then Raise "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else Return (a+b)<br />
<br />
</haskell><br />
<br />
If evalE matches an Add it will check if evaluating the first part<br />
produces a "Raise" or a "Return": in the first case it will return a<br />
"Raise" whose content is the same received. <br />
<br />
If instead the evaluation produces a value of a type matched by<br />
"Return", the evaluator will evaluate the second term of Add.<br />
<br />
If this returns a "Raise", a "Raise" will be returned all the way up<br />
the recursion, otherwise the evaluator will check whether a condition<br />
for raising a "Raise" exists. If not, it will return a "Return" with<br />
the sum inside.<br />
<br />
Test it with:<br />
<br />
evalE (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2)))<br />
<br />
<br />
===The basic evaluator, monadic, with exceptions===<br />
<br />
In order to produce a monadic version of the previous evaluator, the<br />
one that raises exceptions, we just need to abstract out from the<br />
evaluator all that case analysis.<br />
<br />
<haskell><br />
<br />
> data M1 a = Except Exception<br />
> | Ok {showM :: a }<br />
> deriving (Show)<br />
<br />
</haskell><br />
<br />
The data type didn't change at all. Well, we changed the name of the<br />
Return type constructor (now Ok) so that this constructor can coexist<br />
with the previous one in the same Literate Haskell file.<br />
<br />
<div id="MonadicEvalE"><br />
<haskell><br />
<br />
> instance Monad M1 where<br />
> return a = Ok a<br />
> m >>= f = case m of<br />
> Except e -> Except e<br />
> Ok a -> f a<br />
<br />
</haskell><br />
<br />
Binding operations are now very easy. Basically we check:<br />
* if the result of the evaluation of "m" produces an exception (first match: Except e ->...), in which case we return its content by constructing our M1 Int with the "Raise" constructor".<br />
* if the result of the evaluation of "m" is matched with the "Ok" constructor, we get its content and use it to bind the argument of "f" to its value.<br />
<br />
<hask>return a</hask> will just use the Ok type constructor for<br />
inserting "a" (in our case an Int) into M1 Int, the type of our monad.<br />
<br />
<haskell><br />
<br />
> raise :: Exception -> M1 a<br />
> raise e = Except e<br />
<br />
</haskell><br />
<br />
This is just a helper function to construct our "M1 a" type with the<br />
Raise constructor. It takes a string and returns a type (M1 a) to be<br />
matched with the "Raise" constructor.<br />
<br />
<haskell><br />
<br />
> eval_ME :: Term -> M1 Int<br />
> eval_ME (Con a) = do return a<br />
> eval_ME (Add t u) = do a <- eval_ME t<br />
> b <- eval_ME u<br />
> if (a+b) == 42<br />
> then raise "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
</haskell><br />
<br />
The evaluator itself is very simple. We bind "a" with the result of<br />
"eval_ME t", "b" with the result of "eval_ME u", and we check for a<br />
condition: <br />
* if the condition is met we raise an exception, that is to say: we return a value constructed with the "Raise" constructor. This value will be matched by ">>=" in the next recursion. And >>= will just return it all the way up the recursion.<br />
* if the condition is not met, we return a value constructed with the "Return" type constructor and go on with the recursion.<br />
<br />
Run with:<br />
<br />
eval_ME (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2)))<br />
<br />
It is noteworthy the fact that in our datatype definition we used a<br />
label field with a label selector (we called it showM), even though it<br />
was not used in our code. We will use this methodology later on.<br />
<br />
So, just to refresh your memory:<br />
<br />
<haskell><br />
<br />
> data Person = Person {name :: String,<br />
> age :: Int,<br />
> hobby :: String<br />
> } deriving (Show)<br />
<br />
> andreaRossato = Person "Andrea" 37 "Haskell The Monadic Way"<br />
> personName (Person a b c) = a<br />
<br />
</haskell><br />
<br />
will produce:<br />
*TheMonadicWay> andreaRossato<br />
Person {name = "Andrea", age = 37, hobby = "Haskell The Monadic Way"}<br />
*TheMonadicWay> personName andreaRossato<br />
"Andrea"<br />
*TheMonadicWay> name andreaRossato<br />
"Andrea"<br />
*TheMonadicWay> age andreaRossato<br />
37<br />
*TheMonadicWay> hobby andreaRossato<br />
"Haskell The Monadic Way"<br />
*TheMonadicWay> <br />
<br />
<br />
===Monadic evaluator with output and exceptions===<br />
<br />
We will now try to combine the [[The Monadic Way Part I#MonadicEvalIO|output-producing monadic evaluator]] <br />
with [[The Monadic Way Part I#MonadicEvalE| exception producing one]].<br />
<br />
<br />
<haskell><br />
<br />
> data M2 a = Ex Exception<br />
> | Done {unpack :: (a,O) }<br />
> deriving (Show)<br />
<br />
</haskell><br />
<br />
Now we need a datatype with two constructor: one to produce a value<br />
type "M2 a" using "Ex String" and one for value type "M2 a" (Int in<br />
this case) using "Done a".<br />
<br />
'''Note''' that we changed the name of the exception type constructor<br />
from "Raise" to "Ex" just to make the two coexist in the same Literate<br />
Haskell file.<br />
<br />
The constructor "Done a" is defined with a label sector: <hask>Done {unpack :: (a,O)}</hask> <br />
and is equivalent to <hask>Done (a,O)</hask>. <br />
<br />
The only difference is that, this way, we are also defining a method<br />
to retrieve the pair (a,O) (in our case "O" is a synonymous for<br />
String, whereas "a" is a variable type) from an object of type "Done<br />
a".<br />
<br />
<haskell><br />
<br />
> instance Monad M2 where<br />
> return a = Done (a, "")<br />
> m >>= f = case m of<br />
> Ex e -> Ex e<br />
> Done (a, x) -> case (f a) of<br />
> Ex e1 -> Ex e1<br />
> Done (b, y) -> Done (b, x ++ y)<br />
<br />
</haskell><br />
<br />
Now our binding operations gets more complicated by the fact that we<br />
have to concatenate the output, as we did before, '''and''' check for<br />
exceptions.<br />
<br />
It is not possible to do has we did in the [[The Monadic Way Part I#MonadicEvalE| exception producing evaluator]], <br />
where we could check just for "m" (remember the "m" in the first run<br />
stands for "eval t").<br />
<br />
Since at the end we must return the output produced by the evaluation<br />
of "m" ''concatenated'' with the output produced by the evaluation of<br />
"f a" (where "a" is returned by "m", paired with "x" by "Done"), now<br />
we must check if we '''do have''' an output from "f a" produced by<br />
"Done".<br />
<br />
Indeed, now, "f a" can also produce a value constructed by "Ex", and<br />
this value does not contain the pair as the value produced by "Done".<br />
<br />
So, we evaluate "m": <br />
* if we match a value produced by type constructor "Ex" we return a value produced by type constructor "Ex" whose content is the one we extracted in the matching;<br />
* if we match a value produced by "Done" we match the pair it carries "(a,x)" and we analyze what "f a" returns:<br />
** if "f a" returns a value produced by "Ex" we extract the exception and we return it, constructing a value with "Ex"<br />
** if "f a" returns a value produced by "Done" we return "b" and the concatenated "x" and "y". <br />
<br />
And now the evaluator:<br />
<br />
<haskell><br />
<br />
> raise_IOE :: Exception -> M2 a<br />
> raise_IOE e = Ex e<br />
<br />
</haskell><br />
<br />
This is the function to insert in our monad (M2) an exception: we take<br />
a String and produce a value applying the type constructor for<br />
exception "Ex" to its value.<br />
<br />
<haskell><br />
<br />
> print_IOE :: O -> M2 ()<br />
> print_IOE x = Done ((), x)<br />
<br />
</haskell><br />
<br />
The function to produce output is the very same of the one of the [[The Monadic Way Part I#MonadicEvalIO|output-producing monadic evaluator]].<br />
<br />
<haskell><br />
<br />
> eval_IOE :: Term -> M2 Int<br />
> eval_IOE (Con a) = do print_IOE (formatLine (Con a) a)<br />
> return a<br />
> eval_IOE (Add t u) = do a <- eval_IOE t<br />
> b <- eval_IOE u<br />
> let out = formatLine (Add t u) (a + b)<br />
> print_IOE out<br />
> if (a+b) == 42<br />
> then raise_IOE $ out ++ "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
</haskell><br />
<br />
The evaluator procedure did not change very much from the one of the [[The Monadic Way Part I#MonadicEvalIO|output-producing monadic evaluator]].<br />
<br />
We just added the case analysis to see if the condition for raising an exception is met.<br />
<br />
Running with<br />
<br />
eval_IOE (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2)))<br />
<br />
will produce <br />
<br />
Ex "eval (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2))) <= 42 - <br />
The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
<br />
Look at the <hask>let</hask> clause within the do-notation. We do not<br />
need to use the "let ... in" construction: since all bound variables<br />
remain bound within a <hask>do</hask> procedure (see [[The Monadic Way Part I#Bind|here]]), <br />
we do not need the "in" to specify "where" the variable "out" will be bound in!<br />
<br />
==We need a state==<br />
<br />
We will keep on adding complexity to our monadic evaluator and this<br />
time we will add a counter. We just want to count the number of<br />
iterations (the number of times "eval" will be called) needed to<br />
evaluate the expression.<br />
<br />
===The basic evaluator, non monadic, with a counter===<br />
<br />
As before we will start by adding this feature to our [[The Monadic Way Part I#BasicEval|basic evaluator]]. <br />
<br />
A method to count the number of iterations, since the lack of<br />
assignment and destructive updates (such as for i=0;i<10;i++;),<br />
is to add an argument to our function, the initial state, number that<br />
in each call of the function will be increased and passed to the next<br />
function call.<br />
<br />
And so, very simply:<br />
<br />
<haskell><br />
<br />
> -- non monadic<br />
> type St a = State -> (a, State)<br />
> type State = Int<br />
> evalNMS :: Term -> St Int<br />
> evalNMS (Con a) x = (a, x + 1)<br />
> evalNMS (Add t u) x = let (a, y) = evalNMS t x in<br />
> let (b, z) = evalNMS u y in<br />
> (a + b, z +1)<br />
<br />
</haskell><br />
<br />
Now evalNMS takes two arguments: the expression of type Term and an<br />
State (which is a synonymous for Int), and will produce a pair<br />
(a,State), that is to say a pair with a variable type "a" and an Int.<br />
<br />
The operations in the evaluator are very similar to the non monadic [[The Monadic Way Part I#BasivEvalO|output producing evaluator]].<br />
<br />
We are now using the "let ... in" clause, instead of the "where", and we are increasing the counter "z" the comes from the evaluation of the second term, but the basic operation are the same:<br />
* we evaluate "evalNMS t x" where "x" is the initial state, and we match and bind the result in "let (a, y) ... in"<br />
* we evaluate "evalNMS u y", where "y" was bound to the value returned by the previous evaluation, and we match and bind the result in "let (b, z) ... in"<br />
* we return a pair formed by the sum of the result (a+b) and the state z increased by 1. <br />
<br />
Let's try it:<br />
<br />
*TheMonadicWay> evalNMS (Add (Con 10) (Add (Add (Con 20) (Con 10)) (Con 2))) 0<br />
(42,7)<br />
*TheMonadicWay> <br />
<br />
As you see we must pass to "evalNMS"the initial state of our counter: 0.<br />
<br />
Look at the type signature of the function "evalNMS":<br />
<haskell><br />
evalNMS :: Term -> St Int<br />
</haskell><br />
<br />
From this signature you could argue that our function takes only<br />
'''one''' argument. But since our type St is defined with the "type"<br />
keyword, St can be substituted with what comes after the "=" sign. So,<br />
the real type signature of our function is:<br />
<br />
<haskell><br />
evalNMS :: Term -> State -> (Int,State)<br />
</haskell><br />
<br />
<div if="typeNewtype"><br />
Just to refresh your memory:<br />
<br />
<haskell><br />
<br />
> type IamAfunction a = (a -> a)<br />
> newtype IamNotAfunction a = NF (a -> a)<br />
> newtype IamNotAfunctionButYouCanUnPackAndRunMe a = F { unpackAndRun :: (a -> a) }<br />
<br />
> a = \x -> x * x<br />
<br />
> a1 :: IamAfunction Integer<br />
> a1 = a<br />
<br />
> a2 :: IamNotAfunction Integer<br />
> a2 = NF a<br />
<br />
> a3 :: IamNotAfunctionButYouCanUnPackAndRunMe Integer<br />
> a3 = F a<br />
<br />
</haskell><br />
<br />
<br />
*TheMonadicWay> a 4<br />
16<br />
*TheMonadicWay> a1 4<br />
16<br />
*TheMonadicWay> a2 4<br />
<br />
<interactive>:1:0:<br />
The function `a2' is applied to one arguments,<br />
but its type `IamNotAfunction Int' has only 0<br />
In the definition of `it': it = a2 4<br />
*TheMonadicWay> a3 4<br />
<br />
<interactive>:1:0:<br />
The function `a3' is applied to one arguments,<br />
but its type `IamNotAfunctionButYouCanUnPackAndRunMe Int' has only 0<br />
In the definition of `it': it = a3 4<br />
*TheMonadicWay> unpackAndRun a3 4<br />
16<br />
*TheMonadicWay><br />
<br />
This means that "a1" is a partial application hidden by a type<br />
synonymous. <br />
<br />
"a2" and "a3" are not function types. They are types that<br />
have a functional value. <br />
<br />
Moreover, since we defined the type constructor of type<br />
"IamNotAfunctionButYouCanUnPackAndRunMe", F, with a label field, in<br />
that label field we defined a method (a label selector) to "extract"<br />
the function from the type "IamNotAfunctionButYouCanUnPackAndRunMe",<br />
and run it:<br />
<br />
<haskell><br />
unpackAndRun a3 4<br />
</haskell><br />
<br />
And what about "a2"? Is it lost forever?<br />
<br />
Obviously not! We need to write a function that unpacks a type<br />
"IamNotAfunction", using its type constructor NF to match the internal<br />
function:<br />
<br />
<haskell><br />
<br />
> unpackNF :: IamNotAfunction a -> a -> a<br />
> unpackNF (NF f) = f<br />
<br />
</haskell><br />
<br />
and run:<br />
<br />
*TheMonadicWay> unpackNF a2 4<br />
16<br />
*TheMonadicWay> <br />
<br />
As you see, "unpackNF" definition is a partial application: we specify<br />
one argument to get a function that gets another argument.<br />
<br />
A label selector does the same thing.<br />
<br />
Later we will see the importance of this distinction, quite obvious<br />
for haskell gurus, but not for us. Till now.<br />
<br />
===The evaluator, monadic, with a counter===<br />
<br />
We will now rewrite our basic evaluator with the counter in<br />
do-notation.<br />
<br />
As we have seen, in order to do so we need:<br />
* a new type that we must declare as an instance of the Monad class;<br />
* a function for binding method (>>=) and a function for the "return" method, for the instance declaration; <br />
<br />
Now our type will be holding a function that will take the initial<br />
state 0 as we did before.<br />
<br />
In order to simplify the process of unpacking the monad each time to<br />
get the function, we will use a label sector:<br />
<br />
<haskell><br />
<br />
> newtype MS a = MS { unpackMSandRun :: (State -> (a, State)) }<br />
<br />
</haskell><br />
<br />
This is it: MS will be our type constructor for matching and for<br />
building our monad. "unpackMSandRun" will be the method to get the<br />
function out of the monad to feed it with the initial state of the<br />
counter, 0, to get our result.<br />
<br />
Then we need the "return" function that, as we have seen does nothing<br />
but inserting into our monad an Integer:<br />
<br />
<haskell><br />
<br />
> mkMS :: a -> MS a<br />
> mkMS int = MS (\x -> (int, x))<br />
<br />
</haskell><br />
<br />
"mkMS" will just take an Integer "a" and apply the MS type constructor<br />
to our anonymous function that takes an initial state and produces the<br />
final state "x" and the integer "a".<br />
<br />
In other words, we are just creating our monad with inside an Integer.<br />
<br />
Our binding function will be a bit more complicated then before. We<br />
must create a type that holds an anonymous function with elements to<br />
be extracted from our type and passed to the anonymous function that<br />
comes next:<br />
<br />
<haskell><br />
<br />
> bindMS :: MS a -> (a -> MS b) -> MS b<br />
> bindMS monad doNext = MS $ \initialState -> <br />
> let (oldInt, oldState) = unpackMSandRun monad initialState in<br />
> let (newInt, newState) = unpackMSandRun (doNext oldInt) oldState in<br />
> (newInt,newState)<br />
<br />
</haskell><br />
<br />
So, we are creating an anonymous function that will take an initial<br />
state, 0, and return a "newInt" and "newState". <br />
<br />
To do that we need to unpack and run our "monad" against the<br />
initialState in order to get the "oldInt" and the "oldState".<br />
<br />
The "oldInt" will be passed to the "doNext" function (the next<br />
anonymous function in our do block) together with the "oldState" to<br />
get the "newInt" and the "newState".<br />
<br />
We can now declare our type "MS" as an instance of the Monad class:<br />
<haskell><br />
<br />
> instance Monad MS where<br />
> return a = mkMS a<br />
> (>>=) m f = bindMS m f<br />
<br />
</haskell><br />
<br />
We now need a function to increase the counter in our monad from<br />
within a do block:<br />
<br />
<haskell><br />
<br />
> incState :: MS ()<br />
> incState = MS (\s -> ((), s + 1))<br />
<br />
</haskell><br />
<br />
This is easier then it looks like. We use the type constructor MS to<br />
create a function that takes a state an returns a void integer ()<br />
paired with the state increased by one. We do not need any binding,<br />
since we are just modifying the state, an integer, and, in our do<br />
block, we will insert this function before a new line, so that the non<br />
binding ">>" operator will be applied.<br />
<br />
And now the evaluator:<br />
<br />
<haskell><br />
<br />
> evalMS :: Term -> MS Int<br />
> evalMS (Con a) = do incState<br />
> mkMS a<br />
> evalMS (Add t u) = do a <- evalMS t<br />
> b <- evalMS u<br />
> incState <br />
> return (a + b)<br />
<br />
</haskell><br />
<br />
Very easy: we just added the "incState" function before returning the<br />
sum of the evaluation of the Terms of our expression.<br />
<br />
Let's try it:<br />
<br />
*TheMonadicWay> unpackMSandRun (evalMS (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12))))) 0<br />
(54,7)<br />
*TheMonadicWay> <br />
<br />
As you can see, adding a counter makes our binding operations a bit<br />
more complicated by the fact that we have an anonymous function within<br />
our monad. This means that we must recreate that anonymous function in<br />
each step of our do block. This makes "incState" and, as we are going<br />
to see in the next paragraph, the function to produce output a bit<br />
more complicated. Anyway we can handle this complexity quite well, for<br />
now.<br />
<br />
===The monadic evaluator with output and counter in do-notation===<br />
<br />
Adding output to our evaluator is now quite easy. It's just a matter<br />
of adding a field to our type, where we are going to accumulate the<br />
output, and take care of extracting it in our bind function to<br />
concatenate the old one with the new one.<br />
<br />
<haskell><br />
<br />
> newtype Eval_SIO a = Eval_SIO { unPackMSIOandRun :: State -> (a, State, Output) }<br />
<br />
</haskell><br />
<br />
Now our monad contains an anonymous function that takes the initial<br />
state, 0, and will produce the final Integer, the final state and the<br />
concatenated output.<br />
<br />
So, this is bind:<br />
<br />
<haskell><br />
<br />
> bindMSIO monad doNext = <br />
> Eval_SIO (\initialState -><br />
> let (oldInt, oldState, oldOutput) = unPackMSIOandRun monad initialState in<br />
> let (newInt, newState, newOutput) = unPackMSIOandRun (doNext oldInt) oldState in<br />
> (newInt, newState, oldOutput ++ newOutput))<br />
<br />
</haskell><br />
<br />
And this is our "return":<br />
<haskell><br />
<br />
> mkMSIO int = Eval_SIO (\s -> (int, s, ""))<br />
<br />
</haskell><br />
<br />
Now we can declare our type, "Eval_SIO", as an instance of the Monad class:<br />
<br />
<haskell><br />
<br />
> instance Monad Eval_SIO where<br />
> return a = mkMSIO a<br />
> (>>=) m f = bindMSIO m f<br />
<br />
</haskell><br />
<br />
Now, the function to increment the counter will also insert an empty<br />
string "" in our monad: "bind" will take care of concatenating it with<br />
the old output:<br />
<br />
<haskell><br />
<br />
> incSIOstate :: Eval_SIO () <br />
> incSIOstate = Eval_SIO (\s -> ((), s + 1, ""))<br />
<br />
</haskell><br />
<br />
The function to insert some new output will just insert a string into<br />
our monad, together with a void Integer (). Since no binding will<br />
occur (>> will be applied), the () will not be taken into<br />
consideration within the anonymous functions automatically created for<br />
us within the do block:<br />
<br />
<haskell><br />
<br />
> print_SIO :: Output -> Eval_SIO ()<br />
> print_SIO x = Eval_SIO (\s -> ((),s, x))<br />
<br />
</haskell><br />
<br />
And now the evaluator, that puts everything together. As you can see<br />
it did not change too much from the previous versions:<br />
<br />
<haskell><br />
<br />
> eval_SIO :: Term -> Eval_SIO Int<br />
> eval_SIO (Con a) = do incSIOstate<br />
> print_SIO (formatLine (Con a) a)<br />
> return a<br />
> eval_SIO (Add t u) = do a <- eval_SIO t<br />
> b <- eval_SIO u<br />
> incSIOstate<br />
> print_SIO (formatLine (Add t u) (a + b))<br />
> return (a + b)<br />
<br />
</haskell><br />
<br />
Running it will require unpacking the monad and feeding it with the initial state 0:<br />
<br />
unPackMSIOandRun (eval_SIO (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12))))) 0<br />
*TheMonadicWay> unPackMSIOandRun (eval_SIO (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12))))) 0<br />
(54,7,"eval (Con 6) <= 6 - eval (Con 16) <= 16 - <br />
eval (Con 20) <= 20 - <br />
eval (Con 12) <= 12 - <br />
eval (Add (Con 20) (Con 12)) <= 32 - <br />
eval (Add (Con 16) (Add (Con 20) (Con 12))) <= 48 - <br />
eval (Add (Con 6) (Add (Con 16) (Add (Con 20) (Con 12)))) <= 54 - ")<br />
*TheMonadicWay> <br />
<br />
(I formatted the output).<br />
<br />
<br />
==If there's a state we need some discipline: Dealing with complexity==<br />
<br />
'''(Text to be done yet: just a summary)'''<br />
<br />
In order to increase the complexity of our monad now we will try to<br />
mix State (counter), Exceptions and Output.<br />
<br />
This is an email [http://www.haskell.org/pipermail/haskell-cafe/2006-August/017672.html I send to the haskell-cafe mailing list]:<br />
<br />
<pre><br />
Now I'm trying to create a statefull evaluator, with output and<br />
exception, but I'm facing a problem I seem not to be able to<br />
conceptually solve.<br />
<br />
Take the code below.<br />
Now, in order to get it run (and try to debug) the Eval_SOI type has a<br />
Raise constructor that produces the same type of SOIE. Suppose instead it<br />
should be constructing something like Raise "something". <br />
Moreover, I wrote a second version of >>=, commented out.<br />
This is just to help me illustrate to problem I'm facing.<br />
<br />
Now, >>= is suppose to return Raise if "m" is matched against Raise<br />
(second version commented out).<br />
If "m" matches SOIE it must return a SOIE only if "f a" does not<br />
returns a Raise (output must be concatenated).<br />
<br />
I seem not to be able to find a way out. Moreover, I cannot understand<br />
if a way out can be possibly found. Something suggests me it could be<br />
related to that Raise "something".<br />
But my feeling is that functional programming could be something out<br />
of the reach of my mind... by the way, I teach Law, so perhaps you'll<br />
forgive me...;-)<br />
<br />
If you can help me to understand this problem all I can promise is<br />
that I'll mention your help in the tutorial I'm trying to write on<br />
"the monadic way"... that seems to lead me nowhere.<br />
<br />
Thanks for your kind attention.<br />
<br />
Andrea<br />
</pre><br />
<br />
This was the code:<br />
<br />
<haskell><br />
data Eval_SOI a = Raise { unPackMSOIandRun :: State -> (a, State, Output) }<br />
| SOIE { unPackMSOIandRun :: State -> (a, State, Output) }<br />
<br />
instance Monad Eval_SOI where<br />
return a = SOIE (\s -> (a, s, ""))<br />
m >>= f = SOIE (\x -><br />
let (a, y, s1) = unPackMSOIandRun m x in<br />
case f a of<br />
SOIE nextRun -> let (b, z, s2) = nextRun y in <br />
(b, z, s1 ++ s2)<br />
Raise e1 -> e1 y --only this happens<br />
<br />
)<br />
-- (>>=) m f = case m of<br />
-- Raise e -> error "ciao" -- why this is not going to happen?<br />
-- SOIE a -> SOIE (\x -><br />
-- let (a, y, s1) = unPackMSOIandRun m x in<br />
-- let (b, z, s2) = unPackMSOIandRun (f a) y in <br />
-- (b, z, s1 ++ s2)) <br />
<br />
<br />
incSOIstate :: Eval_SOI ()<br />
incSOIstate = SOIE (\s -> ((), s + 1, ""))<br />
<br />
print_SOI :: Output -> Eval_SOI ()<br />
print_SOI x = SOIE (\s -> ((),s, x))<br />
<br />
raise x e = Raise (\s -> (x,s,e))<br />
<br />
eval_SOI :: Term -> Eval_SOI Int<br />
eval_SOI (Con a) = do incSOIstate<br />
print_SOI (formatLine (Con a) a)<br />
return a<br />
eval_SOI (Add t u) = do a <- eval_SOI t<br />
b <- eval_SOI u<br />
incSOIstate<br />
print_SOI (formatLine (Add t u) (a + b))<br />
if (a + b) == 42 <br />
then raise (a+b) " = The Ultimate Answer!!"<br />
else return (a + b)<br />
<br />
runEval exp = case eval_SOI exp of<br />
Raise a -> a 0<br />
SOIE p -> let (result, state, output) = p 0 in<br />
(result,state,output)<br />
<br />
<br />
<br />
--runEval (Add (Con 10) (Add (Con 28) (Add (Con 40) (Con 2))))<br />
</haskell><br />
<br />
This code will produce <br />
<br />
eval (Con 10) <= 10 -<br />
eval (Con 28) <= 28 -<br />
eval (Con 40) <= 40 -<br />
eval (Con 2) <= 2 - = The Ultimate Answer!!<br />
eval (Add (Con 28) (Add (Con 40) (Con 2))) <= 70 -<br />
eval (Add (Con 10) (Add (Con 28) (Add (Con 40) (Con 2)))) <= 80 -<br />
<br />
The exception appears in the output, but executioon is not stopped.<br />
<br />
===Monadic evaluator with output, counter and exception, in do-notation===<br />
<br />
Brian Hulley [http://www.haskell.org/pipermail/haskell-cafe/2006-August/017680.html came up with this solution]:<br />
<br />
<haskell><br />
<br />
> -- thanks to Brian Hulley<br />
> data Result a<br />
> = Good a State Output<br />
> | Bad State Output Exception<br />
> deriving Show<br />
<br />
> newtype Eval_SIOE a = SIOE {runSIOE :: State -> Result a}<br />
<br />
> instance Monad Eval_SIOE where<br />
> return a = SIOE (\s -> Good a s "")<br />
> m >>= f = SIOE $ \x -><br />
> case runSIOE m x of<br />
> Good a y o1 -><br />
> case runSIOE (f a) y of<br />
> Good b z o2 -> Good b z (o1 ++ o2)<br />
> Bad z o2 e -> Bad z (o1 ++ o2) e<br />
> Bad z o2 e -> Bad z o2 e<br />
<br />
> raise_SIOE e = SIOE (\s -> Bad s "" e)<br />
<br />
> incSIOEstate :: Eval_SIOE ()<br />
> incSIOEstate = SIOE (\s -> Good () (s + 1) "")<br />
<br />
> print_SIOE :: Output -> Eval_SIOE ()<br />
> print_SIOE x = SIOE (\s -> Good () s x)<br />
<br />
<br />
> eval_SIOE :: Term -> Eval_SIOE Int<br />
> eval_SIOE (Con a) = do incSIOEstate<br />
> print_SIOE (formatLine (Con a) a)<br />
> return a<br />
> eval_SIOE (Add t u) = do a <- eval_SIOE t<br />
> b <- eval_SIOE u<br />
> incSIOEstate<br />
> let out = formatLine (Add t u) (a + b)<br />
> print_SIOE out<br />
> if (a+b) == 42<br />
> then raise_SIOE $ out ++ "The Ultimate Answer Has Been Computed!! Now I'm tired!"<br />
> else return (a + b)<br />
<br />
> runEval exp = case runSIOE (eval_SIOE exp) 0 of<br />
> Bad s o e -> "Error at iteration n. " ++ show s ++ <br />
> " - Output stack = " ++ o ++ <br />
> " - Exception = " ++ e<br />
> Good a s o -> "Result = " ++ show a ++ <br />
> " - Iterations = " ++ show s ++ " - Output = " ++ o<br />
<br />
</haskell><br />
<br />
Run with runEval (Add (Con 18) (Add (Con 12) (Add (Con 10) (Con 2))))<br />
<br />
==Suggested readings==<br />
<br />
:Cale Gibbard, [[Monads as containers]]<br />
:Jeff Newbern, [http://haskell.org/all_about_monads/html/contmonad.html All About Monads]<br />
:[[IO inside]]<br />
:[http://sigfpe.blogspot.com/2006/08/you-could-have-invented-monads-and.html You Could Have Invented Monads! (And Maybe You Already Have.) by sigfpe]<br />
<br />
<br />
==Acknowledgments==<br />
<br />
Thanks to Neil Mitchell, Daniel Fisher, Bulat Ziganzhin, Brian Hulley<br />
and Udo Stenzel for the invaluable help they gave, in the<br />
[http://www.haskell.org/mailman/listinfo/haskell-cafe haskell-cafe mailing list], <br />
in understanding this topic.<br />
<br />
I couldn't do it without their help.<br />
<br />
Obviously errors are totally mine. But this is a wiki so, please,<br />
correct them!<br />
<br />
- [[User:AndreaRossato|Andrea Rossato]]<br />
<br />
[[Category:Tutorials]]<br />
[[Category:Monad]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=The_Monadic_Way&diff=14653The Monadic Way2007-07-24T22:20:23Z<p>BrettGiles: Heading case</p>
<hr />
<div>'''Note''' Since the size of the previous file was getting too big for a wiki, the tutorial has been divided into two parts: [[The Monadic Way Part I]] and [[The Monadic Way Part II]]. See below for some introductory remarks.<br />
<br />
'''Contents'''<br />
<br />
;[[Meet Bob The Monadic Lover]]<br />
:A (supposed-to-be) funny and short introduction to Monads, with code but without any reference to category theory: what monads look like and what they are useful for, from the perspective of a ... lover. It could be an introduction to "The Monadic Way" tutorial.<br />
<br />
;[[The Monadic Way Part I]]<br />
:In the first part of the tutorial we will start from a very simple evaluator that will be transformed into a monadic evaluator with an increasing number of features: output, exceptions, and state: a very simple counter for tracking the number of recursions of the evaluation precess.<br />
<br />
;[[The Monadic Way Part II]]<br />
:In the second part of the tutorial we will see how to take complexity out of our monadic evaluator with the use of monadic transformers, and specifically StateT. This part is just a skeleton, since, for the time being, it contains only the code.<br />
<br />
<br />
==Preliminary remarks==<br />
<br />
When I started writing this tutorial I though that the only way to<br />
explain monads to a newcomer was to show them from the inside, with<br />
the use of lambda abstraction. Not only because this is the way Philip<br />
Wedler's<br />
[http://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf paper] <br />
adopts, but also because I believed, and still believe, that the<br />
only way to understand what bind (>>=) does is to explain it as a<br />
function that takes a monad and an anonymous function.<br />
<br />
I had this feeling because I am a newcomer, and this is the way I came to understand monads.<br />
<br />
I did not received very much feedback for this tutorial, and I must<br />
admit that I would like to. But one person, on the haskell-cafe<br />
mailing list, [http://www.haskell.org/pipermail/haskell-cafe/2006-September/017740.html told me]<br />
that:<br />
<pre><br />
imho your tutorial makes the error that is a very typical: when you<br />
write your tutorial you already know what are monads and what the<br />
program you will construct at the end. but your reader don't know all these!<br />
for such fresh reader this looks as you made some strange steps, write<br />
some ugly code and he doesn't have chances to understand that this ugly<br />
code is written just to show that this can be simplified by using monads.<br />
</pre><br />
<br />
I believe that Bulat is right. In this tutorial you go through some<br />
code that is '''really''' ugly and then, with some kind of magic, it<br />
turns out in the (redundant but) clean evaluator of the end of [[The Monadic Way Part II]].<br />
<br />
I took that mail as a challenge and <br />
[http://www.haskell.org/pipermail/haskell-cafe/2006-September/017778.html I responded] <br />
by writing [[Meet Bob The Monadic Lover]].<br />
<br />
In "Meet Bob" the code is clean, variable names are very descriptive,<br />
and you see that I can create a monad without any use of lambda<br />
abstraction.<br />
<br />
Bind (in "Meet Bob" is askLover) now takes a monad and a partial<br />
application, not an anonymous function.<br />
<br />
Obviously you can see an anonymous function as a partial application.<br />
<br />
The problem, I think, is that, in "Meet Bob", you cannot understand<br />
the strict relation between what I did before and what I do when I<br />
start using the "do-notation". You see that the same functions are<br />
being used ("tellMyself" and "newLove"), but "andrea <- tellMyself 1"<br />
is not explained. It's just magic.<br />
<br />
The fact is that you cannot understand "andrea <- tellMyself 1"<br />
without the use of lambda abstraction.<br />
<br />
I should have written an intermediate step, something like this:<br />
<haskell><br />
drunk = do newLove "Paula " >><br />
(tellLover 1 10) >>= \paula -><br />
(tellMyself 3) >>= \lorena -> tellMyself (paula + lorena)<br />
<br />
</haskell><br />
<br />
With this approach I think you can understand '''why and how''' you<br />
come to write something like this:<br />
<haskell><br />
drunk = do newLove "Paula "<br />
paula <- (tellLover 1 10)<br />
lorena <- tellMyself 3<br />
tellMyself (paula + lorena)<br />
</haskell><br />
<br />
That is to say, in this way you can see a do block as a series of<br />
nested anonymous functions whose arguments are bound to some value by<br />
the application of >>=. Anonymous functions that bind to some value<br />
the variables appearing after the "->" ("paula" and "lorena").<br />
<br />
To summarize, I think that even if you can start using monads without<br />
understanding that what happens inside a "do" block is strictly<br />
related with lambda calculus, I don't think you can claim you<br />
understand monads just because you are using them. <br />
<br />
And I'm quite sure that if a problem arises somewhere you can have a<br />
very difficult time in trying to find out what the problem is. This is<br />
even more true when you start doing monadic transformations.<br />
<br />
==How to explain monads to newcomers?==<br />
<br />
Monads are not an impossible-to-understand-unless-you-have-a-phd<br />
topic. I don't know if I can claim I'm a living proof of this<br />
assumption, since I have a PhD. But please take into account that I<br />
have a PhD in Comparative Private Law! Nothing related to computer<br />
science. And I claim I understand monads.<br />
<br />
Moreover, since I have come to understand them, I think I can try to<br />
explain them to newcomers like me. This is why I started writing this<br />
tutorial.<br />
<br />
Still, in order to understand them I studied, and I studied hard. I<br />
wanted to understand, it was difficult, and I kept studying. Going<br />
back to the foundation when needed.<br />
<br />
So, I cannot explain monads to you unless you are willing to study. I can<br />
show you the way, but you must take your time and follow that way.<br />
<br />
==What do I need to know to understand monads?==<br />
<br />
===Functional programming===<br />
<br />
First you need at least a basic understanding of functional<br />
programming. <br />
<br />
This is going to be the easiest step, because there is an invaluable<br />
resource available on line for free.<br />
<br />
This is what I did: I spent 20 hours of my life watching the Video<br />
Lectures by Hal Abelson and Gerald Jay Sussman on<br />
[http://swiss.csail.mit.edu/classes/6.001/abelson-sussman-lectures/ Structure and Interpretation of Computer Programs].<br />
<br />
This course, and the annexed text book (I did not read it entirely),<br />
are an amazing introduction to computer science: you start by learning<br />
some basic Scheme and then Abelson and Sussman will bring you, step by<br />
step, to understand evaluation, interpretation and compilation of Lisp<br />
(Scheme) code.<br />
<br />
The course is clear, interesting, funny and will provide you with a<br />
basic, but strong, understanding of functional programming.<br />
<br />
Believe me: if you like programming but don't have a computer science<br />
curriculum, you'll find out that spending 20 hours of your life to<br />
watch that course has been the most productive investment of your<br />
learning life.<br />
<br />
===My problem with Haskell===<br />
<br />
I find Haskell an amazingly expressive programming language. It makes<br />
it incredibly easy to perform very difficult tasks, just like monads,<br />
for instance.<br />
<br />
The problem is that, in doing so, it makes it difficult to understand<br />
Haskell to newcomers.<br />
<br />
I must confess that tutorials and other learning material are quite<br />
dissatisfying on this regards too.<br />
<br />
Since Haskell seems to make easy what is not easy, these tutorial take<br />
the "it's easy" approach.<br />
<br />
I will give you an example. I think that the<br />
[http://www.cs.utah.edu/~hal/htut/ "Yet Another Haskell Tutorial"] is<br />
a really good attempt to explain Haskell, and if you want to<br />
understand this tutorial you need to read it at least for getting a<br />
good understanding of the Haskell type system. <br />
<br />
The tutorial explains monads and explains the "do notation" in terms<br />
of lambda abstraction (par. 9.1, p. 120). Still, to the lambda<br />
operator ("\") the tutorial dedicates only 17 lines in par. 4.4.1.<br />
Moreover "\" is explained just as another way of creating functions.<br />
<br />
This probably makes sense for a functional programmer who is studying<br />
Haskell for the first time. But, on the other side it will make the<br />
newcomer, who's not a functional programmer, believe that explaining<br />
monads in terms of "\" is just ugly, and definitely not Haskell.<br />
<br />
This is my problem with Haskell: it hides complexity with<br />
constructions like "let...in", "where", "do".<br />
<br />
Still I believe that if you want to use those constructions you must<br />
know what they do. And they do ugly stuff like the one you'll be<br />
looking at in this tutorial.<br />
<br />
I am not saying that this is ''the'' way to learn Haskell. I'm just<br />
saying that this is the way I'm learning Haskell. And this is the way<br />
this tutorial has been written.<br />
<br />
===Starting from the inside or the outside?===<br />
<br />
In This tutorial I show monads from their inside. In "Meet Bob" I do<br />
the opposite. As I said I think (and I did it on purpose) that after<br />
reading "Meet Bob" you can have a general idea of what a monad is, but<br />
you need to go inside a monad to see how it works.<br />
<br />
As a suggestion, I'd invite you to start with "Meet Bob", and then<br />
procede with the tutorial.<br />
<br />
I hope the these two approaches will give you an overall image of a<br />
monad.<br />
<br />
===Prerequisites===<br />
<br />
As I said, in order to understand this tutorial you need:<br />
* a basic understanding of functional programming (this is required to understand Haskell after all)<br />
* a basic understanding of the type system:<br />
** how to create new types (with "data" and "newtype")<br />
** how to use type constructors to construct and to match types and their internal components<br />
** how to use a label field to retrieve a type internal component<br />
* a basic understanding of lambda abstraction<br />
<br />
I hope I'll be able to write a short introductory summary to these<br />
topics (I will put it below this introductory remarks).<br />
<br />
Have fun with Haskell!<br />
<br />
- [[User:AndreaRossato|Andrea Rossato]]<br />
<br />
[[Category:Tutorials]]<br />
[[Category:Idioms]]<br />
[[Category:Monad]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=HaskellWiki_talk:Guidelines&diff=14652HaskellWiki talk:Guidelines2007-07-24T18:04:39Z<p>BrettGiles: /* Page nameing */ Notes about why adding the guideline for renaming.</p>
<hr />
<div>==Headlines==<br />
<br />
[[User:BrettGiles|Brett]], this is not to offend you. It just expresses my conviction. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]]<br />
<br />
:Not to worry [[User:Wolfgang Jeltsch|Wolfgang]] - I never take offence :) - My thoughts on the usage of level 2 only were primarily due to the size balance, but also I note this is a guideline for the original mediawiki site. Does anyone know why that is? [[User:BrettGiles|BrettGiles]] 22:11, 25 February 2006 (UTC)<br />
<br />
::No idea, but it seems loose to me. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 22:40, 25 February 2006 (UTC)<br />
<br />
:::I did some research on [http://meta.wikimedia.org/wiki/Help_talk:Section metawiki] and this is the reason they start at level 2. ''"So that when a user without CSS, or a text-mode browser, or a screen reader visits, they'll be presented with a page that at least has a logical document flow."'' From what I can tell, by default, the page title is rendered as a '''h1''' element. So are single '''=''' headings. Double '''==''' are '''h2''' and so on. So from that point of view it does make sense to start at two equals. I think the real issue is that the software is slightly broken in not generating an '''h2''' for a single equals sign. So, what do you think? [[User:BrettGiles|BrettGiles]] 22:36, 26 February 2006 (UTC)<br />
<br />
::::I prefer starting with ==, like Wikipedia. &mdash;[[User:Ashley Y|Ashley Y]] 00:52, 2 March 2006 (UTC)<br />
<br />
::::MediaWiki is broken in not creating an '''h2''' element for a headline with single equal signs. So we should work around this brokeness by making our top-level headlines <tt>==</tt> headlines. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 21:22, 8 March 2006 (UTC)<br />
<br />
:::::I've added a respective section to [[HaskellWiki:Guidelines]]. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 21:40, 8 March 2006 (UTC)<br />
<br />
==Page nameing and renaming==<br />
Apparently the last rename I did so offended the author that they quit the wiki. I used to follow the guideline I just added on the main page, but had never got a response before. However, considering the size of the wiki and the number of new users (especially those that seem to not know there are guidelines :), perhaps it is time to re-institute the practice. --[[User:BrettGiles|BrettGiles]] 18:04, 24 July 2007 (UTC)<br />
<br />
==Official guidelines?==<br />
<br />
What makes a guidline an "official" guidline? What's the process? &mdash;[[User:Ashley Y|Ashley Y]] 00:53, 2 March 2006 (UTC)<br />
<br />
:I suspect that a large number of the users / contributors to this site have an academic background. My experience with academia is that some kind of consensus based decision is the most successful at getting the decision adopted. In a community like this wiki, I’m not sure how to get that. We could send out notices on the various mailing lists, we could post notes on the front page and probably other ways as well. Like any consensus decision making it would take a long time. On the other hand, those that support the site could just be autocratic, set the rule and if there is too much flak, change it. <br />
:As to what actually makes an "official" guidline, I think it is up to the '''sysops''' whether we even have such a thing. The word tends to mean that '''sysops''' are required to monitor and fix the site when these are not followed. So, we might not even want to go to official, stay at unofficial and just let the community grow the guidlines (and do the monitoring) as they see fit. Sometimes, a certain level of anarchy works fine.[[User:BrettGiles|BrettGiles]] 16:06, 2 March 2006 (UTC)<br />
::I think that the traditional consensus decision making process is too slow. In addition, not everyone is interested in every guideline question, so it is not sensible to bother everyone with each of these questions. Therefore, it seems to me that it is better to follow your “autocracy approach”. And I also doubt that it is sensible to let some sysops decide about what guidelines are official. At least, this would be a bit contrary to the wiki approach, in my opinion. So I propose that users are allowed to set up guidelines they think of as sensible—possibly after some short discussion—and to declare them as official. If others don't like the guidelines, the guidelines can still be discussed (again) and changed. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 21:22, 8 March 2006 (UTC)<br />
<br />
OK. Everything on the project page should have a consensus. Everything else should be discussed here. I have adjusted the project page accordingly. &mdash;[[User:Ashley Y|Ashley Y]] 06:34, 3 March 2006 (UTC)<br />
:What is the “project page”? -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 21:22, 8 March 2006 (UTC)<br />
::Ah, I understand. It's [[HaskellWiki:Guidelines]]. -- [[User:Wolfgang Jeltsch|Wolfgang Jeltsch]] 21:40, 8 March 2006 (UTC)<br />
<br />
== Headlines ==<br />
<br />
Each page has a title which is automatically shown near the top of the page (currently centered and in red). So it doesn't make sense to put a single level 1 headline at the top of the page. (At the moment, you will see this on a few pages of this wiki. I suppose this is a legacy which comes from copying content from the old website to this wiki.)<br />
<br />
For top-level structuring, level 1 headlines (the ones denoted by single equals signs in the source) should be used. It is semantically incorrect to use level 2 headlines for this purpose. I note that level 1 headlines are currently rather large and in a font that might not be preferable. However, the solution to this is not to refrain from using level 1 headlines but to change the stylesheet appropriately. ''&mdash;says [[User:Wolfgang Jeltsch]]''<br />
<br />
:Note that is is currently being discussed. Level 1 (single equals) create an <tt>&lt;h1&gt;</tt> heading, which is the same level as the page title. We may (or may not:) switch to the standard of starting at level 2 (double equals) ''&mdash;says [[User:BrettGiles]]''<br />
<br />
:I prefer starting with level 2 as per Wikipedia. I consider the page title to be implicitly level 1 (whether it gets rendered as h1 or not). &mdash;[[User:Ashley Y|Ashley Y]] 06:34, 3 March 2006 (UTC)<br />
<br />
<br />
== Wiki Bug ==<br />
Try giving a Haskell example with the greater than or the less than sign in it. It clashes with the HTML rendering! -- says [[User:Uchchwhash|Pirated Dreams]] 04:22, 17 March 2006 (UTC)</div>BrettGileshttps://wiki.haskell.org/index.php?title=HaskellWiki:Guidelines&diff=14651HaskellWiki:Guidelines2007-07-24T18:01:33Z<p>BrettGiles: /* Page titles */ guidelines for renaming process - will add comments on this talk as to why.</p>
<hr />
<div>Here you will find guidelines for editing this wiki.<br />
<br />
== General principles ==<br />
<br />
Please bear in mind that our first audience is those expecting a web-site on Haskell and not necessarily interested in this wiki thing. The default style, for instance, tries to make the wiki-ness as discreet as possible for readers not logged in.<br />
<br />
== Page structure ==<br />
<br />
There shall not be a single top level section. If you divide a page into sections, please introduce multiple sections at the top level. That means, the sections should form a true forest instead of just a tree. Using a single top level section is very untypical and is also not needed for giving the whole text a headline since there is the page title for this issue.<br />
<br />
== Page titles ==<br />
<br />
These are some guidelines for page titles:<br />
# Page titles not only affect a page's URL but they are also shown at the top of the page. Therefore, it is important that a page title is a title, not a mnemonic path name. I strongly doubt that we need such mnemonic names but if they are introduced they should denote only redirects to the actual page.<br />
# On the other hand, it is good if titles are not unnecessarily long so that URLs have reasonable size.<br />
# Titles should use sentence-style capitalization (see [http://en.wikipedia.org/wiki/Capitalization#Headings_and_publication_titles]). Capitalizing more words seems to be only appropriate in larger documents like books. If slashes are used to denote hierarchy, each part of the hierarchical title should be handled as if it were a title itself, i.e., its first word should be capitalized.<br />
<br />
===Page titles of "quiz" pages===<br />
The de-facto standard for quiz and contest pages is capitalization of each word in the page title, apparently contradicting the "Sentence case" guideline above. This is based on the idea that each of the quiz / contest / shootout problems is considered a proper name, hence should be capitalized. Similarly, the solutions are named "Solution John Doe", where the author of the solution is John Doe, again requiring capitalization of all words.<br />
<br />
==Renaming of page titles==<br />
When doing a signficant renaming of a page, (i.e., something more than just correcting the case as per the guidelines), use the "Discuss this page" link to suggest the new title and the reasons why. After a reasonable amount of time, if there are no objections, go ahead and move / rename the page.<br />
<br />
== Categories ==<br />
<br />
In order to ease navigation in the wiki, several categories are<br />
introduced. Whenever possible, please classify your page under one of<br />
the categories. For example, if you write a page about your new project,<br />
you can add it to the [http://haskell.org/haskellwiki/Category:Applications Applications category]<br />
by adding the following text to your page:<br />
<br />
<haskell><br />
[[Category:Applications]]<br />
</haskell><br />
<br />
All known categories are in the wiki special page [[Special:Categories]].<br />
<br />
== Headlines ==<br />
<br />
Level 1 headlines (the ones written as <code>= Headline =</code>) shall not be used. Instead, a headline which is logically at the top level shall be implemented as a level 2 headline (i.e, as <code>== Headline ==</code>). The reason is that the page title and the level 1 headlines are both implemented as <tt>h1</tt> elements in the page's HTML. They are distinguished by using different HTML classes indeed, but this distinction is too light. For example, a browser which doesn't support CSS would probably render page titles and level 1 headlines the same way.<br />
<br />
Like page titles, headlines shall use sentence-style capitalization [http://en.wikipedia.org/wiki/Capitalization#Headings_and_publication_titles].<br />
<br />
== Links ==<br />
<br />
Please don't use the click here approach for inserting links. Instead, formulate your text as if you would put it on paper (where the request to click doesn't make sense) and markup parts of the text (often only single words) as links.<br />
<br />
== Code on the Wiki ==<br />
<br />
As this site is about Haskell, there will obviously be cases where you need to include Haskell (or other) code. Use the appropriate tags for the language (<code>&lt;hask&gt;</code> and <code>&lt;/hask&gt;</code> for inline Haskell, <code>&lt;haskell&gt;</code> and <code>&lt;/haskell&gt;</code> for full blocks.) See, for example, [[HaskellWiki:Style test]].<br />
<br />
Code examples should be kept as small and relevant as possible.<br />
=== Large blocks of code ===<br />
<br />
Rarely will people wade through a large piece of code, unless they are looking for something to implement or actually use. For those cases, consider using the Wiki [[Special:Upload | file upload]] capability to load the source code and then provide a link to that on the page. As an example, see the [[Alex/Wrapper monadUser]] page. <br />
<br />
This will contribute to the readability of the page.<br />
== Punctuation ==<br />
<br />
If would be great if you would use the punctuation symbols which are used in professional documents like “, ” and — instead of their ASCII workarounds like " and -. If you use an X server with a keymap like mine, you can get “ and ” with AltGr&nbsp;+&nbsp;V and AltGr&nbsp;+&nbsp;B.<br />
<br />
== Editing ==<br />
<br />
When editing the wiki, the bottom of the editing page has a place to put a summary. It is considered good form to put a one line comment about any changes you are making. As well, you have the capability to mark an edit as ''minor''. Please use this only for changing format, spelling, fixing bad links or minor word re-arrangement. It should not be used when adding whole new sections, a significant number of links, new pages or rewrites of the page.<br />
<br />
[[Help:Editing|Information]] on editor support for the Haskell wiki.</div>BrettGileshttps://wiki.haskell.org/index.php?title=User_talk:BrettGiles&diff=14598User talk:BrettGiles2007-07-22T21:12:55Z<p>BrettGiles: Agree with reasons.</p>
<hr />
<div>Why did you rename the page I created, X Window Programming in Haskell, to X Window Programming?<br />
<br />
It is not about X Window programming, but about X Window Programming IN HASKELL!<br />
: Hi Andrea. If you feel strongly about it, please go ahead and rename it back to "X window programming in Haskell". I had two reasons. First, it did not follow the capitalization standards for pages here. Second, there have been various discussions that "In Haskell", "Haskell..." etc., page titles are redundant as the site is dedicated to Haskell. I'll post this on your talk page as well, in case you aren't monitoring this one. --[[User:BrettGiles|BrettGiles]] 20:02, 22 July 2007 (UTC)<br />
<br />
Hi, it's not a matter of feeling strongly about it, but the fact that pages are getting indexed by search engines outside this wiki too, and titles matter: someone looking for a page on X window programming may just be misguided by the page title of a tutorial that only discuss the way of programming the X server from the Haskell side but whose title suggests it is dedicated to discussing general X programming issues. <br />
As the guidelines say "it is important that a page title is a title".<br />
While I may understand your argument for pages discussing specific Haskell issues, for a page discussing bindings to a library in a foreign language it seems plainly wrong to me.<br />
Still I'm open to discussion (which means: we discuss and ''then'' a decision is taken). AndreaRossato 23:02 22 July 2007 (CEST)<br />
<br />
: I already renamed the page to the original title, but with sentence capitalization (I didn't see it in the guidelines, I must confess). --AndreaRossato - same time as before.<br />
:The argument makes sense. I'm happy leaving it as is.--[[User:BrettGiles|BrettGiles]] 21:12, 22 July 2007 (UTC)</div>BrettGileshttps://wiki.haskell.org/index.php?title=User_talk:AndreaRossato&diff=14595User talk:AndreaRossato2007-07-22T20:03:48Z<p>BrettGiles: Answering.</p>
<hr />
<div>: Hi Andrea. If you feel strongly about it, please go ahead and rename it back to "X window programming in Haskell". I had two reasons. First, it did not follow the capitalization standards for pages here. Second, there have been various discussions that "In Haskell", "Haskell..." etc., page titles are redundant as the site is dedicated to Haskell. I'll post this on your talk page as well, in case you aren't monitoring this one. --[[User:BrettGiles|BrettGiles]] 20:03, 22 July 2007 (UTC)</div>BrettGileshttps://wiki.haskell.org/index.php?title=User_talk:BrettGiles&diff=14594User talk:BrettGiles2007-07-22T20:02:41Z<p>BrettGiles: Answering Andrea Rossato</p>
<hr />
<div>Why did you rename the page I created, X Window Programming in Haskell, to X Window Programming?<br />
<br />
It is not about X Window programming, but about X Window Programming IN HASKELL!<br />
: Hi Andrea. If you feel strongly about it, please go ahead and rename it back to "X window programming in Haskell". I had two reasons. First, it did not follow the capitalization standards for pages here. Second, there have been various discussions that "In Haskell", "Haskell..." etc., page titles are redundant as the site is dedicated to Haskell. I'll post this on your talk page as well, in case you aren't monitoring this one. --[[User:BrettGiles|BrettGiles]] 20:02, 22 July 2007 (UTC)</div>BrettGileshttps://wiki.haskell.org/index.php?title=Talk:Learn_Haskell_in_10_minutes&diff=14590Talk:Learn Haskell in 10 minutes2007-07-22T17:54:02Z<p>BrettGiles: agreewitho comment</p>
<hr />
<div>In [[Learn_Haskell_in_10_minutes#Function_definitions]], the definition of <hask>main</hask> is not a ''function'', but rather an ''IO'' definition. Haskell cleanly separates the notion of "function" from "definition". I suggest renaming this section just "Definitions" and tweaking the explanation. [[User:Conal|Conal]] 13:17, 18 July 2007 (UTC)<br />
:Yes - I agree with Conal and have done a start, albeit without renaming the section to definitions.--[[User:BrettGiles|BrettGiles]] 17:54, 22 July 2007 (UTC)</div>BrettGileshttps://wiki.haskell.org/index.php?title=Learn_Haskell_in_10_minutes&diff=14589Learn Haskell in 10 minutes2007-07-22T17:52:34Z<p>BrettGiles: /* Function definitions */ Applying sensible comment about IO action versus function - probably could use more tweaking.</p>
<hr />
<div>== Overview ==<br />
<br />
Haskell is a functional (that is, everything is done with function calls), statically, implicitly typed ([[type]]s are checked by the compiler, but you don't have to declare them), lazy (nothing is done until it needs to be) language. Its closest popular relative is probably the ML family of languages.<br />
<br />
The most common Haskell compiler is [[GHC]]. You can download GHC from http://www.haskell.org/ghc/download_ghc_661.html . GHC binaries are available for [[GNU/Linux]], [[BSD | FreeBSD]], [[Mac OS X |MacOS]], [[Windows]], and [[Solaris]]. Once you've installed [[GHC]], you get two programs you're interested in right now: <tt>ghc</tt>, and <tt>[[GHC/GHCi | ghci]]</tt>. The first compiles Haskell libraries or applications to binary code. The second is an interpreter that lets you write Haskell code and get feedback right away.<br />
<br />
== Simple expressions ==<br />
<br />
You can type most math expressions directly into <tt>ghci</tt> and get an answer. <tt>Prelude></tt> is the default GHCi prompt.<br />
<br />
Prelude> <hask>3 * 5</hask><br />
15<br />
Prelude> <hask>4 ^ 2 - 1</hask><br />
15<br />
Prelude> <hask>(1 - 5)^(3 * 2 - 4)</hask><br />
16<br />
<br />
Strings are in "double quotes." You can concatenate them with <hask>++</hask>.<br />
<br />
Prelude> <hask>"Hello"</hask><br />
"Hello"<br />
Prelude> <hask>"Hello" ++ ", Haskell"</hask><br />
"Hello, Haskell"<br />
<br />
Calling [[function]]s is done by putting the arguments directly after the function. There are no parentheses as part of the function call:<br />
<br />
Prelude> <hask>succ 5</hask><br />
6<br />
Prelude> <hask>truncate 6.59</hask><br />
6<br />
Prelude> <hask>round 6.59</hask><br />
7<br />
Prelude> <hask>sqrt 2</hask><br />
1.4142135623730951<br />
Prelude> <hask>not (5 < 3)</hask><br />
True<br />
Prelude> <hask>gcd 21 14</hask><br />
7<br />
<br />
== The console ==<br />
<br />
[[Introduction to IO |I/O actions]] can be used to read from and write to the console. Some common ones include:<br />
<br />
Prelude> <hask>putStrLn "Hello, Haskell"</hask><br />
Hello, Haskell<br />
Prelude> <hask>putStr "No newline"</hask><br />
No newlinePrelude> <hask>print (5 + 4)</hask><br />
9<br />
Prelude> <hask>print (1 < 2)</hask><br />
True<br />
<br />
The <hask>putStr</hask> and <hask>putStrLn</hask> functions output strings to the terminal. The <hask>print</hask> function outputs any type of value. (If you <hask>print</hask> a string, it will have quotes around it.)<br />
<br />
If you need multiple I/O actions in one expression, you can use a <hask>do</hask> block. Actions are separated by semicolons.<br />
<br />
Prelude> <hask>do { putStr "2 + 2 = " ; print (2 + 2) }</hask><br />
2 + 2 = 4<br />
Prelude> <hask>do { putStrLn "ABCDE" ; putStrLn "12345" }</hask><br />
ABCDE<br />
12345<br />
<br />
Reading can be done with <hask>getLine</hask> (which gives back a <hask>String</hask>) or <hask>readLn</hask> (which gives back whatever type of value you want). The <hask> <- </hask> symbol is used to assign a name to the result of an I/O action.<br />
<br />
Prelude> <hask>do { n <- readLn ; print (n^2) }</hask><br />
4<br />
16<br />
<br />
(The 4 was input. The 16 was a result.)<br />
<br />
There is actually another way to write <hask>do</hask> blocks. If you leave off the braces and semicolons, then indentation becomes significant. This doesn't work so well in <tt>ghci</tt>, but try putting the file in a source file (say, <tt>Test.hs</tt>) and build it.<br />
<br />
<haskell><br />
main = do putStrLn "What is 2 + 2?"<br />
x <- readLn<br />
if x == 4<br />
then putStrLn "You're right!"<br />
else putStrLn "You're wrong!"<br />
</haskell><br />
<br />
You can build with <tt>ghc --make Test.hs</tt>, and the result will be called <tt>Test</tt>. (On [[Windows]], <tt>Test.exe</tt>) You get an <hask>if</hask> expression as a bonus.<br />
<br />
The first non-space character after <hask>do</hask> is special. In this case, it's the <tt>p</tt> from <hask>putStrLn</hask>. Every line that starts in the same column as that <hask>p</p> is another statement in the <hask>do</hask> block. If you indent more, it's part of the previous statement. If you indent less, it ends the <hask>do</code> block. This is called "layout", and Haskell uses it to avoid making you put in statement terminators and braces all the time. (The <hask>then</hask> and <hask>else</hask> phrases have to be indented for this reason: if they started in the same column, they'd be separate statements, which is wrong.)<br />
<br />
(Note: Do '''not''' indent with tabs if you're using layout. It technically still works if your tabs are 8 spaces, but it's a bad idea. Also, don't use proportional fonts -- which apparently some people do, even when programming!)<br />
<br />
== Simple types ==<br />
<br />
So far, not a single [[type]] declaration has been mentioned. That's because Haskell does type inference. You generally don't have to declare types unless you want to. If you do want to declare types, you use <hask>::</hask> to do it.<br />
<br />
Prelude> <hask>5 :: Int</hask><br />
5<br />
Prelude> <hask>5 :: Double</hask><br />
5.0<br />
<br />
[[Type]]s (and type [[class]]es, discussed later) always start with upper-case letters in Haskell. Variables always start with lower-case letters. This is a rule of the language, not a [[Studly capitals|naming convention]].<br />
<br />
You can also ask <tt>ghci</tt> what type it has chosen for something. This is useful because you don't generally have to declare your types.<br />
<br />
Prelude> :t <hask>True</hask><br />
<hask>True :: Bool</hask><br />
Prelude> :t <hask>'X'</hask><br />
<hask>'X' :: Char</hask><br />
Prelude> :t <hask>"Hello, Haskell"</hask><br />
<hask>"Hello, Haskell" :: [Char]</hask><br />
<br />
(In case you noticed, <hask>[Char]</hask> is another way of saying <hask>String</hask>. See the [[#Structured data|section on lists]] later.)<br />
<br />
Things get more interesting for numbers.<br />
<br />
Prelude> :t <hask>42</hask><br />
<hask>42 :: (Num t) => t</hask><br />
Prelude> :t <hask>42.0</hask><br />
<hask>42.0 :: (Fractional t) => t</hask><br />
Prelude> :t <hask>gcd 15 20</hask><br />
<hask>gcd 15 20 :: (Integral t) => t</hask><br />
<br />
These types use "type classes." They mean:<br />
<br />
* <hask>42</hask> can be used as any numeric type. (This is why I was able to declare <hask>5</hask> as either an <hask>Int</hask> or a <hask>Double</hask> earlier.)<br />
* <hask>42.0</hask> can be any fractional type, but not an integral type.<br />
* <hask>gcd 15 20</hask> (which is a function call, incidentally) can be any integral type, but not a fractional type.<br />
<br />
There are five numeric types in the Haskell "prelude" (the part of the library you get without having to import anything):<br />
<br />
* <hask>Int</hask> is an integer with at least 30 bits of precision.<br />
* <hask>Integer</hask> is an integer with unlimited precision.<br />
* <hask>Float</hask> is a single precision floating point number.<br />
* <hask>Double</hask> is a double precision floating point number.<br />
* <hask>Rational</hask> is a fraction type, with no rounding error.<br />
<br />
All five are '''instances''' of the <hask>Num</hask> type class. The first two are '''instances''' of <hask>Integral</hask>, and the last three are '''instances''' of <hask>Fractional</hask>.<br />
<br />
Putting it all together,<br />
<br />
Prelude> <hask>gcd 42 35 :: Int</hask><br />
7<br />
Prelude> <hask>gcd 42 35 :: Double</hask><br />
<br />
<interactive>:1:0:<br />
No instance for (Integral Double)<br />
<br />
The final type worth mentioning here is <hask>()</hask>, pronounced "unit." It only has one value, also written as <hask>()</hask> and pronounced "unit."<br />
<br />
Prelude> <hask>()</hask><br />
<hask>()</hask><br />
Prelude> :t <hask>()</hask><br />
<hask>() :: ()</hask><br />
<br />
You can think of this as similar to the <tt>void</tt> keyword in C family languages. You can return <hask>()</hask> from an I/O action if you don't want to return anything.<br />
<br />
== Structured data ==<br />
<br />
Basic data types can be easily combined in two ways: lists, which go in [square brackets], and tuples, which go in (parentheses).<br />
<br />
Lists are used to hold multiple values of the same type.<br />
<br />
Prelude> <hask>[1, 2, 3]</hask><br />
[1,2,3]<br />
Prelude> <hask>[1 .. 5]</hask><br />
[1,2,3,4,5]<br />
Prelude> <hask>[1, 3 .. 10]</hask><br />
[1,3,5,7,9]<br />
Prelude> <hask>[True, False, True]</hask><br />
[True,False,True]<br />
<br />
Strings are just lists of characters.<br />
<br />
Prelude> <hask>['H', 'e', 'l', 'l', 'o']</hask><br />
"Hello"<br />
<br />
The <hask>:</hask> operator appends an item to the beginning of a list. (It is Haskell's version of the <tt>cons</tt> function in the Lisp family of languages.)<br />
<br />
Prelude> <hask>'C' : ['H', 'e', 'l', 'l', 'o']</hask><br />
"CHello"<br />
<br />
Tuples hold a fixed number of values, which can have different types.<br />
<br />
Prelude> <hask>(1, True)</hask><br />
(1,True)<br />
Prelude> <hask>zip [1 .. 5] ['a' .. 'e']</hask><br />
[(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e')]<br />
<br />
The last example used <hask>zip</hask>, a library function that turns two lists into a list of tuples.<br />
<br />
The types are probably what you'd expect.<br />
<br />
Prelude> :t <hask>['a' .. 'c']</hask><br />
<hask>['a' .. 'c'] :: [Char]</hask><br />
Prelude> :t <hask>[('x', True), ('y', False)]</hask><br />
<hask>[('x', True), ('y', False)] :: [(Char, Bool)]</hask><br />
<br />
Lists are used a lot in Haskell. There are several functions that do nice things with them.<br />
<br />
Prelude> <hask>[1 .. 5]</hask><br />
<hask>[1,2,3,4,5]</hask><br />
Prelude> <hask>map (+ 2) [1 .. 5]</hask><br />
<hask>[3,4,5,6,7]</hask><br />
Prelude> <hask>filter (> 2) [1 .. 5]</hask><br />
<hask>[3,4,5]</hask><br />
<br />
There are two nice functions on ordered pairs (tuples of two elements):<br />
<br />
Prelude> <hask>fst (1, 2)</hask><br />
<hask>1</hask><br />
Prelude> <hask>snd (1, 2)</hask><br />
<hask>2</hask><br />
Prelude> <hask>map fst [(1, 2), (3, 4), (5, 6)]</hask><br />
<hask>[1,3,5]</hask><br />
<br />
Also see [[how to work on lists]]<br />
<br />
== [[Function]] definitions ==<br />
<br />
We wrote a definition of an [[Introduction to Haskell IO/Actions |IO action]] earlier, called <hask>main</hask>:<br />
<br />
<haskell><br />
main = do putStrLn "What is 2 + 2?"<br />
x <- readLn<br />
if x == 4<br />
then putStrLn "You're right!"<br />
else putStrLn "You're wrong!"<br />
</haskell><br />
<br />
Now, let's supplement it by actully writing a ''[[function]]'' definition and call it <hask>factorial</hask>. I'm also adding a module header, which is good form.<br />
<br />
<haskell><br />
module Main where<br />
<br />
factorial n = if n == 0 then 1 else n * factorial (n - 1)<br />
<br />
main = do putStrLn "What is 5! ?"<br />
x <- readLn<br />
if x == factorial 5<br />
then putStrLn "You're right!"<br />
else putStrLn "You're wrong!"<br />
</haskell><br />
<br />
Build again with <tt>ghc --make Test.hs</tt>. And,<br />
<br />
$ ./Test<br />
What is 5! ?<br />
120<br />
You're right!<br />
<br />
There's a function. Just like the built-in functions, it can be called as <hask>factorial 5</hask> without needing parentheses.<br />
<br />
Now ask <tt>ghci</tt> for the [[type]].<br />
<br />
$ ghci Test.hs<br />
<< GHCi banner >><br />
Ok, modules loaded: Main.<br />
Prelude Main> :t <hask>factorial</hask><br />
<hask>factorial :: (Num a) => a -> a</hask><br />
<br />
Function types are written with the argument type, then <hask> -> </hask>, then the result type. (This also has the type class <hask>Num</hask>.)<br />
<br />
Factorial can be simplified by writing it with case analysis.<br />
<br />
<haskell><br />
factorial 0 = 1<br />
factorial n = n * factorial (n - 1)<br />
</haskell><br />
<br />
== Convenient syntax ==<br />
<br />
A couple extra pieces of [[:Category:Syntax |syntax]] are helpful.<br />
<br />
<haskell><br />
secsToWeeks secs = let perMinute = 60<br />
perHour = 60 * perMinute<br />
perDay = 24 * perHour<br />
perWeek = 7 * perday<br />
in secs * perWeek<br />
</haskell><br />
<br />
The <hask>let</hask> expression defines temporary names. (This is using layout again. You could use {braces}, and separate the names with parentheses, if you prefer.)<br />
<br />
<haskell><br />
classify age = case age of 0 -> "newborn"<br />
1 -> "infant"<br />
2 -> "toddler"<br />
_ -> "senior citizen"<br />
</haskell><br />
<br />
The <hask>case</hask> expression does a multi-way branch. The special label <hask>_</hask> means "anything else".<br />
<br />
== Using libraries ==<br />
<br />
Everything used so far in this tutorial is part of the [[Prelude]], which is the set of Haskell functions that are always there in any program.<br />
<br />
The best road from here to becoming a very productive Haskell programmer (aside from practice!) is becoming familiar with other [[Applications and libraries | libraries]] that do the things you need. Documentation on the standard libraries is at [http://haskell.org/ghc/docs/latest/html/libraries/ http://haskell.org/ghc/docs/latest/html/libraries/]. There are modules there with:<br />
<br />
* [[Applications and libraries/Data structures |Useful data structures]]<br />
* [[Applications and libraries/Concurrency and parallelism |Concurrent and parallel programming]]<br />
* [[Applications and libraries/GUI libraries | Graphics and GUI libraries]]<br />
* [[Applications and libraries/Network | Networking, POSIX, and other system-level stuff]]<br />
* Two test frameworks, QuickCheck and HUnit<br />
* Regular expressions and predictive parsers<br />
* More...<br />
<br />
<haskell><br />
module Main where<br />
<br />
import qualified Data.Map as M<br />
<br />
errorsPerLine = M.fromList<br />
[ ("Chris", 472), ("Don", 100), ("Simon", -5) ]<br />
<br />
main = do putStrLn "Who are you?"<br />
name <- getLine<br />
case M.lookup name errorsPerLine of<br />
Nothing -> putStrLn "I don't know you"<br />
Just n -> do putStr "Errors per line: "<br />
print n<br />
</haskell><br />
<br />
The <hask>import</hask> says to use code from <hask>Data.Map</hask> and that it will be prefixed by <hask>M</hask>. (That's necessary because some of the functions have the same names as functions from the prelude. Most libraries don't need the <hask>as</hask> part.)<br />
<br />
If you want something that's not in the standard library, try looking at http://hackage.haskell.org/packages/hackage.html or this wiki's [[applications and libraries]] page. This is a collection of many different libraries written by a lot of people for Haskell. Once you've got a library, extract it and switch into that directory and do this:<br />
<br />
runhaskell Setup configure<br />
runhaskell Setup build<br />
runhaskell Setup install<br />
<br />
On a UNIX system, you may need to be root for that last part.<br />
<br />
== Topics that don't fit in 10 minute limit ==<br />
<br />
* [[:Category:Language | Advanced data types]]<br />
** Arithmetic lists<br />
** [[List comprehension]]s<br />
** [[Type#Type and newtype | Type synonyms]]<br />
** [[Type|data vs newtype]] (and [[Newtype|here]])<br />
** [[Class |Type classes and instances]]<br />
* [[:Category:Syntax |Advanced syntax]]<br />
** [[Operator]]s<br />
** [[Infix operator |(+) and `foo`]]<br />
** [[Fixity declaration]]s<br />
* Advanced functions<br />
** [[Currying]]<br />
** [[Lambda abstraction]]s<br />
** [[Section of an infix operator |Sections]]<br />
* [[:Category:Monad |Monads]]<br />
* [[Tutorials/Programming Haskell/String IO |File I/O]]<br />
** Reading files<br />
** Writing Files<br />
<br />
[[Category:Tutorials]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=Infix_operator&diff=14588Infix operator2007-07-22T17:46:43Z<p>BrettGiles: Categorize, link to "section of an infix operator"</p>
<hr />
<div>[[Category:Syntax]] [[Category:Glossary]]<br />
== Overview ==<br />
<br />
Functions in Haskell are usually called using prefix notation, or the function name followed by its arguments. However, some functions, like +, are called with infix notation, or putting the function name between its two arguments.<br />
<br />
== Using infix functions with prefix notation ==<br />
<br />
Putting parenthesis around an infix operator converts it into a prefix function:<br />
<br />
Prelude> (+) 1 2<br />
3<br />
Prelude> (*) 3 4<br />
12<br />
<br />
== Using prefix functions with infix notation ==<br />
<br />
Putting ` marks around a prefix function allows us to use it like an infix function:<br />
<br />
Prelude> let concatPrint x y = putStrLn $ (++) x y<br />
Prelude> concatPrint "a" "b"<br />
ab<br />
Prelude> "a" `concatPrint` "b"<br />
ab<br />
<br />
Note that you can only do this with a function that takes two arguments.<br />
<br />
==Section==<br />
See the article [[section of an infix operator]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=Learn_Haskell_in_10_minutes&diff=14587Learn Haskell in 10 minutes2007-07-22T17:44:38Z<p>BrettGiles: /* Topics that don't fit in 10 minute limit */ link update</p>
<hr />
<div>== Overview ==<br />
<br />
Haskell is a functional (that is, everything is done with function calls), statically, implicitly typed ([[type]]s are checked by the compiler, but you don't have to declare them), lazy (nothing is done until it needs to be) language. Its closest popular relative is probably the ML family of languages.<br />
<br />
The most common Haskell compiler is [[GHC]]. You can download GHC from http://www.haskell.org/ghc/download_ghc_661.html . GHC binaries are available for [[GNU/Linux]], [[BSD | FreeBSD]], [[Mac OS X |MacOS]], [[Windows]], and [[Solaris]]. Once you've installed [[GHC]], you get two programs you're interested in right now: <tt>ghc</tt>, and <tt>[[GHC/GHCi | ghci]]</tt>. The first compiles Haskell libraries or applications to binary code. The second is an interpreter that lets you write Haskell code and get feedback right away.<br />
<br />
== Simple expressions ==<br />
<br />
You can type most math expressions directly into <tt>ghci</tt> and get an answer. <tt>Prelude></tt> is the default GHCi prompt.<br />
<br />
Prelude> <hask>3 * 5</hask><br />
15<br />
Prelude> <hask>4 ^ 2 - 1</hask><br />
15<br />
Prelude> <hask>(1 - 5)^(3 * 2 - 4)</hask><br />
16<br />
<br />
Strings are in "double quotes." You can concatenate them with <hask>++</hask>.<br />
<br />
Prelude> <hask>"Hello"</hask><br />
"Hello"<br />
Prelude> <hask>"Hello" ++ ", Haskell"</hask><br />
"Hello, Haskell"<br />
<br />
Calling [[function]]s is done by putting the arguments directly after the function. There are no parentheses as part of the function call:<br />
<br />
Prelude> <hask>succ 5</hask><br />
6<br />
Prelude> <hask>truncate 6.59</hask><br />
6<br />
Prelude> <hask>round 6.59</hask><br />
7<br />
Prelude> <hask>sqrt 2</hask><br />
1.4142135623730951<br />
Prelude> <hask>not (5 < 3)</hask><br />
True<br />
Prelude> <hask>gcd 21 14</hask><br />
7<br />
<br />
== The console ==<br />
<br />
[[Introduction to IO |I/O actions]] can be used to read from and write to the console. Some common ones include:<br />
<br />
Prelude> <hask>putStrLn "Hello, Haskell"</hask><br />
Hello, Haskell<br />
Prelude> <hask>putStr "No newline"</hask><br />
No newlinePrelude> <hask>print (5 + 4)</hask><br />
9<br />
Prelude> <hask>print (1 < 2)</hask><br />
True<br />
<br />
The <hask>putStr</hask> and <hask>putStrLn</hask> functions output strings to the terminal. The <hask>print</hask> function outputs any type of value. (If you <hask>print</hask> a string, it will have quotes around it.)<br />
<br />
If you need multiple I/O actions in one expression, you can use a <hask>do</hask> block. Actions are separated by semicolons.<br />
<br />
Prelude> <hask>do { putStr "2 + 2 = " ; print (2 + 2) }</hask><br />
2 + 2 = 4<br />
Prelude> <hask>do { putStrLn "ABCDE" ; putStrLn "12345" }</hask><br />
ABCDE<br />
12345<br />
<br />
Reading can be done with <hask>getLine</hask> (which gives back a <hask>String</hask>) or <hask>readLn</hask> (which gives back whatever type of value you want). The <hask> <- </hask> symbol is used to assign a name to the result of an I/O action.<br />
<br />
Prelude> <hask>do { n <- readLn ; print (n^2) }</hask><br />
4<br />
16<br />
<br />
(The 4 was input. The 16 was a result.)<br />
<br />
There is actually another way to write <hask>do</hask> blocks. If you leave off the braces and semicolons, then indentation becomes significant. This doesn't work so well in <tt>ghci</tt>, but try putting the file in a source file (say, <tt>Test.hs</tt>) and build it.<br />
<br />
<haskell><br />
main = do putStrLn "What is 2 + 2?"<br />
x <- readLn<br />
if x == 4<br />
then putStrLn "You're right!"<br />
else putStrLn "You're wrong!"<br />
</haskell><br />
<br />
You can build with <tt>ghc --make Test.hs</tt>, and the result will be called <tt>Test</tt>. (On [[Windows]], <tt>Test.exe</tt>) You get an <hask>if</hask> expression as a bonus.<br />
<br />
The first non-space character after <hask>do</hask> is special. In this case, it's the <tt>p</tt> from <hask>putStrLn</hask>. Every line that starts in the same column as that <hask>p</p> is another statement in the <hask>do</hask> block. If you indent more, it's part of the previous statement. If you indent less, it ends the <hask>do</code> block. This is called "layout", and Haskell uses it to avoid making you put in statement terminators and braces all the time. (The <hask>then</hask> and <hask>else</hask> phrases have to be indented for this reason: if they started in the same column, they'd be separate statements, which is wrong.)<br />
<br />
(Note: Do '''not''' indent with tabs if you're using layout. It technically still works if your tabs are 8 spaces, but it's a bad idea. Also, don't use proportional fonts -- which apparently some people do, even when programming!)<br />
<br />
== Simple types ==<br />
<br />
So far, not a single [[type]] declaration has been mentioned. That's because Haskell does type inference. You generally don't have to declare types unless you want to. If you do want to declare types, you use <hask>::</hask> to do it.<br />
<br />
Prelude> <hask>5 :: Int</hask><br />
5<br />
Prelude> <hask>5 :: Double</hask><br />
5.0<br />
<br />
[[Type]]s (and type [[class]]es, discussed later) always start with upper-case letters in Haskell. Variables always start with lower-case letters. This is a rule of the language, not a [[Studly capitals|naming convention]].<br />
<br />
You can also ask <tt>ghci</tt> what type it has chosen for something. This is useful because you don't generally have to declare your types.<br />
<br />
Prelude> :t <hask>True</hask><br />
<hask>True :: Bool</hask><br />
Prelude> :t <hask>'X'</hask><br />
<hask>'X' :: Char</hask><br />
Prelude> :t <hask>"Hello, Haskell"</hask><br />
<hask>"Hello, Haskell" :: [Char]</hask><br />
<br />
(In case you noticed, <hask>[Char]</hask> is another way of saying <hask>String</hask>. See the [[#Structured data|section on lists]] later.)<br />
<br />
Things get more interesting for numbers.<br />
<br />
Prelude> :t <hask>42</hask><br />
<hask>42 :: (Num t) => t</hask><br />
Prelude> :t <hask>42.0</hask><br />
<hask>42.0 :: (Fractional t) => t</hask><br />
Prelude> :t <hask>gcd 15 20</hask><br />
<hask>gcd 15 20 :: (Integral t) => t</hask><br />
<br />
These types use "type classes." They mean:<br />
<br />
* <hask>42</hask> can be used as any numeric type. (This is why I was able to declare <hask>5</hask> as either an <hask>Int</hask> or a <hask>Double</hask> earlier.)<br />
* <hask>42.0</hask> can be any fractional type, but not an integral type.<br />
* <hask>gcd 15 20</hask> (which is a function call, incidentally) can be any integral type, but not a fractional type.<br />
<br />
There are five numeric types in the Haskell "prelude" (the part of the library you get without having to import anything):<br />
<br />
* <hask>Int</hask> is an integer with at least 30 bits of precision.<br />
* <hask>Integer</hask> is an integer with unlimited precision.<br />
* <hask>Float</hask> is a single precision floating point number.<br />
* <hask>Double</hask> is a double precision floating point number.<br />
* <hask>Rational</hask> is a fraction type, with no rounding error.<br />
<br />
All five are '''instances''' of the <hask>Num</hask> type class. The first two are '''instances''' of <hask>Integral</hask>, and the last three are '''instances''' of <hask>Fractional</hask>.<br />
<br />
Putting it all together,<br />
<br />
Prelude> <hask>gcd 42 35 :: Int</hask><br />
7<br />
Prelude> <hask>gcd 42 35 :: Double</hask><br />
<br />
<interactive>:1:0:<br />
No instance for (Integral Double)<br />
<br />
The final type worth mentioning here is <hask>()</hask>, pronounced "unit." It only has one value, also written as <hask>()</hask> and pronounced "unit."<br />
<br />
Prelude> <hask>()</hask><br />
<hask>()</hask><br />
Prelude> :t <hask>()</hask><br />
<hask>() :: ()</hask><br />
<br />
You can think of this as similar to the <tt>void</tt> keyword in C family languages. You can return <hask>()</hask> from an I/O action if you don't want to return anything.<br />
<br />
== Structured data ==<br />
<br />
Basic data types can be easily combined in two ways: lists, which go in [square brackets], and tuples, which go in (parentheses).<br />
<br />
Lists are used to hold multiple values of the same type.<br />
<br />
Prelude> <hask>[1, 2, 3]</hask><br />
[1,2,3]<br />
Prelude> <hask>[1 .. 5]</hask><br />
[1,2,3,4,5]<br />
Prelude> <hask>[1, 3 .. 10]</hask><br />
[1,3,5,7,9]<br />
Prelude> <hask>[True, False, True]</hask><br />
[True,False,True]<br />
<br />
Strings are just lists of characters.<br />
<br />
Prelude> <hask>['H', 'e', 'l', 'l', 'o']</hask><br />
"Hello"<br />
<br />
The <hask>:</hask> operator appends an item to the beginning of a list. (It is Haskell's version of the <tt>cons</tt> function in the Lisp family of languages.)<br />
<br />
Prelude> <hask>'C' : ['H', 'e', 'l', 'l', 'o']</hask><br />
"CHello"<br />
<br />
Tuples hold a fixed number of values, which can have different types.<br />
<br />
Prelude> <hask>(1, True)</hask><br />
(1,True)<br />
Prelude> <hask>zip [1 .. 5] ['a' .. 'e']</hask><br />
[(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e')]<br />
<br />
The last example used <hask>zip</hask>, a library function that turns two lists into a list of tuples.<br />
<br />
The types are probably what you'd expect.<br />
<br />
Prelude> :t <hask>['a' .. 'c']</hask><br />
<hask>['a' .. 'c'] :: [Char]</hask><br />
Prelude> :t <hask>[('x', True), ('y', False)]</hask><br />
<hask>[('x', True), ('y', False)] :: [(Char, Bool)]</hask><br />
<br />
Lists are used a lot in Haskell. There are several functions that do nice things with them.<br />
<br />
Prelude> <hask>[1 .. 5]</hask><br />
<hask>[1,2,3,4,5]</hask><br />
Prelude> <hask>map (+ 2) [1 .. 5]</hask><br />
<hask>[3,4,5,6,7]</hask><br />
Prelude> <hask>filter (> 2) [1 .. 5]</hask><br />
<hask>[3,4,5]</hask><br />
<br />
There are two nice functions on ordered pairs (tuples of two elements):<br />
<br />
Prelude> <hask>fst (1, 2)</hask><br />
<hask>1</hask><br />
Prelude> <hask>snd (1, 2)</hask><br />
<hask>2</hask><br />
Prelude> <hask>map fst [(1, 2), (3, 4), (5, 6)]</hask><br />
<hask>[1,3,5]</hask><br />
<br />
Also see [[how to work on lists]]<br />
<br />
== [[Function]] definitions ==<br />
<br />
We wrote a [[function]] earlier, called <hask>main</hask>:<br />
<br />
<haskell><br />
main = do putStrLn "What is 2 + 2?"<br />
x <- readLn<br />
if x == 4<br />
then putStrLn "You're right!"<br />
else putStrLn "You're wrong!"<br />
</haskell><br />
<br />
Let's write another, and call it <hask>factorial</hask>. I'm also adding a module header, which is good form.<br />
<br />
<haskell><br />
module Main where<br />
<br />
factorial n = if n == 0 then 1 else n * factorial (n - 1)<br />
<br />
main = do putStrLn "What is 5! ?"<br />
x <- readLn<br />
if x == factorial 5<br />
then putStrLn "You're right!"<br />
else putStrLn "You're wrong!"<br />
</haskell><br />
<br />
Build again with <tt>ghc --make Test.hs</tt>. And,<br />
<br />
$ ./Test<br />
What is 5! ?<br />
120<br />
You're right!<br />
<br />
There's a function. Just like the built-in functions, it can be called as <hask>factorial 5</hask> without needing parentheses.<br />
<br />
Now ask <tt>ghci</tt> for the [[type]].<br />
<br />
$ ghci Test.hs<br />
<< GHCi banner >><br />
Ok, modules loaded: Main.<br />
Prelude Main> :t <hask>factorial</hask><br />
<hask>factorial :: (Num a) => a -> a</hask><br />
<br />
Function types are written with the argument type, then <hask> -> </hask>, then the result type. (This also has the type class <hask>Num</hask>.)<br />
<br />
Factorial can be simplified by writing it with case analysis.<br />
<br />
<haskell><br />
factorial 0 = 1<br />
factorial n = n * factorial (n - 1)<br />
</haskell><br />
<br />
== Convenient syntax ==<br />
<br />
A couple extra pieces of [[:Category:Syntax |syntax]] are helpful.<br />
<br />
<haskell><br />
secsToWeeks secs = let perMinute = 60<br />
perHour = 60 * perMinute<br />
perDay = 24 * perHour<br />
perWeek = 7 * perday<br />
in secs * perWeek<br />
</haskell><br />
<br />
The <hask>let</hask> expression defines temporary names. (This is using layout again. You could use {braces}, and separate the names with parentheses, if you prefer.)<br />
<br />
<haskell><br />
classify age = case age of 0 -> "newborn"<br />
1 -> "infant"<br />
2 -> "toddler"<br />
_ -> "senior citizen"<br />
</haskell><br />
<br />
The <hask>case</hask> expression does a multi-way branch. The special label <hask>_</hask> means "anything else".<br />
<br />
== Using libraries ==<br />
<br />
Everything used so far in this tutorial is part of the [[Prelude]], which is the set of Haskell functions that are always there in any program.<br />
<br />
The best road from here to becoming a very productive Haskell programmer (aside from practice!) is becoming familiar with other [[Applications and libraries | libraries]] that do the things you need. Documentation on the standard libraries is at [http://haskell.org/ghc/docs/latest/html/libraries/ http://haskell.org/ghc/docs/latest/html/libraries/]. There are modules there with:<br />
<br />
* [[Applications and libraries/Data structures |Useful data structures]]<br />
* [[Applications and libraries/Concurrency and parallelism |Concurrent and parallel programming]]<br />
* [[Applications and libraries/GUI libraries | Graphics and GUI libraries]]<br />
* [[Applications and libraries/Network | Networking, POSIX, and other system-level stuff]]<br />
* Two test frameworks, QuickCheck and HUnit<br />
* Regular expressions and predictive parsers<br />
* More...<br />
<br />
<haskell><br />
module Main where<br />
<br />
import qualified Data.Map as M<br />
<br />
errorsPerLine = M.fromList<br />
[ ("Chris", 472), ("Don", 100), ("Simon", -5) ]<br />
<br />
main = do putStrLn "Who are you?"<br />
name <- getLine<br />
case M.lookup name errorsPerLine of<br />
Nothing -> putStrLn "I don't know you"<br />
Just n -> do putStr "Errors per line: "<br />
print n<br />
</haskell><br />
<br />
The <hask>import</hask> says to use code from <hask>Data.Map</hask> and that it will be prefixed by <hask>M</hask>. (That's necessary because some of the functions have the same names as functions from the prelude. Most libraries don't need the <hask>as</hask> part.)<br />
<br />
If you want something that's not in the standard library, try looking at http://hackage.haskell.org/packages/hackage.html or this wiki's [[applications and libraries]] page. This is a collection of many different libraries written by a lot of people for Haskell. Once you've got a library, extract it and switch into that directory and do this:<br />
<br />
runhaskell Setup configure<br />
runhaskell Setup build<br />
runhaskell Setup install<br />
<br />
On a UNIX system, you may need to be root for that last part.<br />
<br />
== Topics that don't fit in 10 minute limit ==<br />
<br />
* [[:Category:Language | Advanced data types]]<br />
** Arithmetic lists<br />
** [[List comprehension]]s<br />
** [[Type#Type and newtype | Type synonyms]]<br />
** [[Type|data vs newtype]] (and [[Newtype|here]])<br />
** [[Class |Type classes and instances]]<br />
* [[:Category:Syntax |Advanced syntax]]<br />
** [[Operator]]s<br />
** [[Infix operator |(+) and `foo`]]<br />
** [[Fixity declaration]]s<br />
* Advanced functions<br />
** [[Currying]]<br />
** [[Lambda abstraction]]s<br />
** [[Section of an infix operator |Sections]]<br />
* [[:Category:Monad |Monads]]<br />
* [[Tutorials/Programming Haskell/String IO |File I/O]]<br />
** Reading files<br />
** Writing Files<br />
<br />
[[Category:Tutorials]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=Infix_operator&diff=14585Infix operator2007-07-22T17:43:33Z<p>BrettGiles: Infix operators moved to Infix operator</p>
<hr />
<div>== Overview ==<br />
<br />
Functions in Haskell are usually called using prefix notation, or the function name followed by its arguments. However, some functions, like +, are called with infix notation, or putting the function name between its two arguments.<br />
<br />
== Using infix functions with prefix notation ==<br />
<br />
Putting parenthesis around an infix operator converts it into a prefix function:<br />
<br />
Prelude> (+) 1 2<br />
3<br />
Prelude> (*) 3 4<br />
12<br />
<br />
== Using prefix functions with infix notation ==<br />
<br />
Putting ` marks around a prefix function allows us to use it like an infix function:<br />
<br />
Prelude> let concatPrint x y = putStrLn $ (++) x y<br />
Prelude> concatPrint "a" "b"<br />
ab<br />
Prelude> "a" `concatPrint` "b"<br />
ab<br />
<br />
Note that you can only do this with a function that takes two arguments.</div>BrettGileshttps://wiki.haskell.org/index.php?title=Infix_operators&diff=14586Infix operators2007-07-22T17:43:33Z<p>BrettGiles: Infix operators moved to Infix operator: Singularity of case expected.</p>
<hr />
<div>#redirect [[Infix operator]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=X_window_programming_in_Haskell&diff=14583X window programming in Haskell2007-07-22T17:41:08Z<p>BrettGiles: X Window Programming in Haskell moved to X window programming</p>
<hr />
<div>==Writing an X application with Haskell Xlib bindings==<br />
<br />
This tutorial is a side product of the research and the learning<br />
experience of writing a<br />
[http://hackage.haskell.org/cgi-bin/hackage-scripts/package/xmobar status bar] <br />
for the [http://xmonad.org XMonad Window Manager], the<br />
first WM written in Haskell.<br />
<br />
It will show you how to write a simple X application using the low<br />
level Xlib library. The goal is to write a simple text base clock,<br />
that will display the system time, to be run on top of every other<br />
applications, like a status bar.<br />
<br />
While the application is fairly simple, still it will require us to<br />
get to know quite a lot of the details that must be taken into account<br />
when writing a properly working X application.<br />
<br />
Obviously some understanding of X and Xlib is required.<br />
<br />
These are some links that can be used as reference:<br />
<br />
* [http://www.tronche.com/gui/x/xlib/ The Xlib Manual]: this is the reference manual, and you should look up here every function that we are going to use in this tutorial.<br />
* [http://en.wikipedia.org/wiki/Xlib Xlib (Wikipedia)]<br />
* [http://en.wikipedia.org/wiki/X_Window_System_core_protocol X Window System core protocol (Wikipedia)]<br />
* [http://www.sbin.org/doc/Xlib/ Xlib Programming Manual]: specifically the [http://www.sbin.org/doc/Xlib/chapt_02.html Chapter 2 X Concepts]<br />
<br />
This tutorial is dedicated to the intermediate Haskell coder. While I<br />
will try to write the simplest code I can (probably it will even look<br />
the dumbest, but that's me), I'm not going into much details about the<br />
Haskell part.<br />
<br />
What are we going to learn:<br />
* how to create a window and set, or change, its attributes;<br />
* how to draw in that window, specifically some text, with some properties, like fonts or colors;<br />
* how to properly update the window;<br />
* how to handle events, like a mouse button press.<br />
<br />
In order to compile the following code examples you need at least:<br />
<br />
* [http://hackage.haskell.org/cgi-bin/hackage-scripts/package/X11 X11], the Haskell binding to the X11 graphics library.<br />
* [http://hackage.haskell.org/cgi-bin/hackage-scripts/package/X11-extras X11-extras]: will be required in some examples. This library provides missing bindings to the X11 graphics library and is actively developed by Spencer Janssen at the time of this writing. Some functions needed in this tutorial can be found only in the darcs repository of X11-extras: [http://darcs.haskell.org/~sjanssen/X11-extras http://darcs.haskell.org/~sjanssen/X11-extras]. Read carefully the README before installing.<br />
<br />
<br />
<br />
==Hello World==<br />
<br />
Let's start from the usual simple "Hello World"<br />
<br />
<haskell><br />
<br />
module Main where<br />
import Graphics.X11.Xlib<br />
import System.Exit (exitWith, ExitCode(..))<br />
import Control.Concurrent (threadDelay)<br />
<br />
main :: IO ()<br />
main =<br />
do dpy <- openDisplay ""<br />
let dflt = defaultScreen dpy<br />
border = blackPixel dpy dflt<br />
background = whitePixel dpy dflt<br />
rootw <- rootWindow dpy dflt<br />
win <- createSimpleWindow dpy rootw 0 0 100 100 1 border background<br />
setTextProperty dpy win "Hello World" wM_NAME <br />
mapWindow dpy win<br />
sync dpy False<br />
threadDelay (10 * 1000000)<br />
exitWith ExitSuccess<br />
<br />
</haskell><br />
<br />
The first function, <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Display.html#v%3AopenDisplay openDisplay],<br />
is the interface to the Xlib function <br />
[http://www.tronche.com/gui/x/xlib/display/opening.html XOpenDisplay()], <br />
and opens a connection to the X sever that controls a display. The connection is returned and bound to dpy. By applying <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Display.html#v%3AdefaultScreen defaultScreen], <br />
the interface to <br />
[http://www.tronche.com/gui/x/xlib/display/display-macros.html#DefaultScreen XDefaultScreen], <br />
we get the default screen, that is required in many of the following functions.<br />
With<br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Display.html#v%3ArootWindow rootWindow], <br />
the interface to <br />
[http://www.tronche.com/gui/x/xlib/display/display-macros.html#RootWindow XRootWindow()], <br />
we get the root window. We need it in order to set the parent window in the most important function of the above code: <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Window.html#v%3AcreateSimpleWindow createSimpleWindow], <br />
the interface to <br />
[http://www.tronche.com/gui/x/xlib/window/XCreateWindow.html XCreateSimpleWindow].<br />
<br />
This function takes, as arguments: the display, the parent window of<br />
the window to be created, the x position, the y position, the width,<br />
the height, the border width, the border pixel and the background<br />
pixel.<br />
<br />
The x and y positions are relative to the upper left corner of the<br />
parent window's inside borders.<br />
<br />
In order to retrieve the values of the black and white pixels for that<br />
specific screen, we use two specific functions:<br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Display.html#v%3AblackPixel blackPixel], <br />
the interface to the X11 library function <br />
[http://www.tronche.com/gui/x/xlib/display/display-macros.html#BlackPixel BlackPixel], <br />
and <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Display.html#v%3AwhitePixel whitePixel], <br />
the interface to the X11 library function <br />
[http://www.tronche.com/gui/x/xlib/display/display-macros.html#WhitePixel WhitePixel]<br />
<br />
The function createSimpleWindow will return the window ID and, with<br />
this ID, we can start manipulating our newly created window, as we do,<br />
in the above code, with the function<br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Misc.html#v%3AsetTextProperty setTextProperty], <br />
interface to the X11 library function <br />
[http://www.tronche.com/gui/x/xlib/ICC/client-to-window-manager/XSetTextProperty.html XSetTextProperty()].<br />
<br />
This function is needed, in our code, to set the window's name, that<br />
your window manager will display on some decoration attached to the<br />
window (other window managers will not display anything, for instance<br />
a tiling WM like [http://xmonad.org XMonad])<br />
<br />
To set the window's name we need to manipulate the <br />
[http://www.tronche.com/gui/x/xlib/ICC/client-to-window-manager/converting-string-lists.html XTextProperty structure]. <br />
<br />
Properties, such as the XTextProperty, have a string name and a<br />
numerical identifier called an atom. An atom is an ID that uniquely<br />
identifies a particular property. Property name strings are typically<br />
all upper case - with the first letter in low case when translated<br />
into Haskell - with words separated by underscores. In our example we<br />
had to set the WM_NAME property to "Hello World".<br />
<br />
Creating and manipulating a window is just the first step to have a<br />
new window displayed. In order for the window to become visible we<br />
must map it with <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Window.html#v%3AmapWindow mapWindow], <br />
the interface to the X11 library function <br />
[http://www.tronche.com/gui/x/xlib/window/XMapWindow.html XMapWindow()]. <br />
This will make the window visible.<br />
<br />
Xlib will not send requests and calls to the Xserver immediately, but<br />
will buffer them and send the full buffer when some given conditions<br />
are met.<br />
<br />
One way to force the flushing of the output buffer is to call <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Event.html#v%3Async sync], <br />
the interface to the X11 library function <br />
[http://www.tronche.com/gui/x/xlib/event-handling/XSync.html XSync()], <br />
which takes 2 arguments: the connection (dpy) and a Boolean value that<br />
indicates whether XSync() must discard all events on the event queue.<br />
<br />
After that the Xserver will eventually display our window. <br />
<br />
The rest of the above example does nothing else but blocking the<br />
program execution for 10 seconds (to let you stare at your newly<br />
created window) and then will exit.<br />
<br />
==Window's attributes==<br />
<br />
Even though in our "Hello World" example we set the window's<br />
dimension, we have no assurance that the Window Manager will respect<br />
our decision.<br />
<br />
[[Xmonad]], for instance, will just create a window<br />
with the dimensions needed to fill its tiled screen, no matter what<br />
you set in createSimpleWindow.<br />
<br />
But we decided to write a small clock that will behave as a status<br />
bar, that is to say, we want to create a window that will not be<br />
managed by a Window Manager.<br />
<br />
In order to achieve this result we need to start dealing with window's<br />
attributes.<br />
<br />
There are two ways of dealing with window's attributes: the first is<br />
to set them at window's creation time, but in that case<br />
createSimpleWindow is not powerful enough.<br />
<br />
The second way is to change window's attributes after the window's has<br />
been created. This second approach is not implemented<br />
[http://hackage.haskell.org/cgi-bin/hackage-scripts/package/X11 X11] but<br />
has been implemented in the darcs version of <br />
[http://hackage.haskell.org/cgi-bin/hackage-scripts/package/X11-extras X11-extras].<br />
<br />
===Setting the window attributes at creation time===<br />
<br />
In order to set window's attributes at creation time, the window must be created with <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Window.html#v%3AcreateWindow createWindow], <br />
the interface to the X11 library function <br />
[http://www.tronche.com/gui/x/xlib/window/XCreateWindow.html XCreateWindow()].<br />
<br />
The type signature of this function is quite long:<br />
<br />
<haskell><br />
<br />
createWindow :: Display -> Window <br />
-> Position -> Position <br />
-> Dimension -> Dimension <br />
-> CInt <br />
-> CInt <br />
-> WindowClass <br />
-> Visual <br />
-> AttributeMask <br />
-> Ptr SetWindowAttributes <br />
-> IO Window<br />
<br />
</haskell><br />
<br />
That is to say:<br />
* the connection and the parent window<br />
* the x and y position (origins in the upper left corner of the inside border of the parent window)<br />
* width and height<br />
* border width<br />
* depth of screen<br />
* the window's class<br />
* the visual<br />
* the attribute mask<br />
* and the pointer to the [http://www.tronche.com/gui/x/xlib/window/attributes/#XSetWindowAttributes XSetWindowAttributes] foreign C structure.<br />
<br />
This last one gives you an idea of the type of operation we must do in<br />
order to create a window (createSimpleWindow is just a wrapper around<br />
this more complicated createWindow, with some default arguments): we<br />
need a function to allocate some memory for the creation of the<br />
foreign C structure, and then manipulate this foreign structure from<br />
within this function.<br />
<br />
The needed function is <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Misc.html#v%3AallocaSetWindowAttributes allocaSetWindowAttributes], <br />
whose type indeed is:<br />
<br />
<haskell><br />
<br />
allocaSetWindowAttributes :: (Ptr SetWindowAttributes -> IO a) -> IO a<br />
<br />
</haskell><br />
<br />
allocaSetWindowAttributes will take a function which takes the pointer<br />
to the foreign structure as its argument. This function will perform<br />
an IO action that is the action returned by allocaSetWindowAttributes.<br />
<br />
In our case allocaSetWindowAttributes will take a function that will<br />
use createWindow to return the new window.<br />
<br />
So, we will need to use createWindow inside allocaSetWindowAttributes.<br />
We will soon see how. But first let's analyze the other arguments of<br />
createWindow.<br />
<br />
The display, the parent window, the coordinates and dimensions are the<br />
same as with createSimpleWindow. But now we must specify the depth of<br />
the screen, the window's class, the visual and the attribute mask. We<br />
also need to manipulate the XSetWindowAttribute after its creation by<br />
allocaSetWindowAttributes, before calling createWindow.<br />
<br />
«The depth is the number of bits available for each pixel to represent color (or gray scales). The visual represents the way pixel values are translated to produce color or monochrome output on the monitor.»( see [http://www.sbin.org/doc/Xlib/chapt_02.html http://www.sbin.org/doc/Xlib/chapt_02.html])<br />
<br />
For the depth we are going to use <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Screen.html#v%3AdefaultDepthOfScreen defaultDepthOfScreen], <br />
interface to the X11 library function <br />
[http://www.tronche.com/gui/x/xlib/display/image-format-macros.html#DefaultDepthOfScreen XDefaultDepthOfScreen()], <br />
to retrieve the default screen depth.<br />
<br />
For the visual we are going to use<br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Screen.html#v%3AdefaultVisualOfScreen defaultVisualOfScreen], <br />
interface to the X11 library function <br />
[http://www.tronche.com/gui/x/xlib/display/image-format-macros.html#DefaultVisualOfScreen DefaultVisualOfScreen].<br />
<br />
The <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Types.html#t%3AWindowClass WindowClass] <br />
can either be copyFromParent, inputOutput, or inputOnly. In the first case the<br />
class is copied from the class of the parent window. An inputOnly<br />
window can only be used for receiving input events. In our code we are<br />
going to use inputOutput windows, windows that can receive input events<br />
and that can also be used to display some output.<br />
<br />
The attributeMask «specifies which window attributes are defined in<br />
the attributes argument. This mask is the bitwise inclusive OR of the<br />
valid attribute mask bits. If value mask is zero, the attributes are<br />
ignored and are not referenced.»<br />
(see [http://www.tronche.com/gui/x/xlib/window/XCreateWindow.html http://www.tronche.com/gui/x/xlib/window/XCreateWindow.html]).<br />
<br />
In other words, in order to set more then one attribute, you need to pass a value mask such as:<br />
<br />
<haskell><br />
<br />
attrmask = cWOverrideRedirect .|. cWBorderPixel .|. cWBackPixel .|. etc ...<br />
<br />
</haskell><br />
<br />
and set each of this attributes within allocaSetWindowAttributes with <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Misc.html#12 specific attributes setting functions].<br />
<br />
Among these functions the one we need: <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Misc.html#v%3Aset_override_redirect set_override_redirect], <br />
whose type is:<br />
<br />
<haskell><br />
<br />
set_override_redirect :: Ptr SetWindowAttributes -> Bool -> IO ()<br />
<br />
</haskell><br />
<br />
This function takes the pointer to the XSetWindowAttributes structure and the flag to be set (True or False).<br />
<br />
For the list of avaliable attributes see<br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Types.html#t%3AAttributeMask the AttributeMask type defnition].<br />
<br />
For their meaning see <br />
[http://www.tronche.com/gui/x/xlib/window/attributes/#XSetWindowAttributes the XSetWindowAttributes structure reference].<br />
<br />
Now, our goal was to create a window that the Window Manager is going<br />
to ignore, and in order to do that all we need to set the attribute<br />
[http://www.tronche.com/gui/x/xlib/window/attributes/override-redirect.html CWOverrideRedirect] <br />
to True. And now we know how to do it.<br />
<br />
Ok, it's time to introduce our function to create new windows with the CWOverrideRedirect set to True<br />
<br />
<haskell><br />
<br />
mkUnmanagedWindow :: Display<br />
-> Screen<br />
-> Window<br />
-> Position<br />
-> Position<br />
-> Dimension<br />
-> Dimension<br />
-> IO Window<br />
mkUnmanagedWindow dpy scr rw x y w h = do<br />
let visual = defaultVisualOfScreen scr<br />
attrmask = cWOverrideRedirect<br />
win <- allocaSetWindowAttributes $ <br />
\attributes -> do<br />
set_override_redirect attributes True<br />
createWindow dpy rw x y w h 0 (defaultDepthOfScreen scr) <br />
inputOutput visual attrmask attributes <br />
return win<br />
<br />
</haskell><br />
<br />
Like simpleCreateWindow, our function is a wrapper around<br />
createWindow, but this time we are manually setting the<br />
CWOverrideRedirect flag.<br />
<br />
As you see our function, unlike createSimpleWindow, does not have,<br />
among its arguments, the background and the border pixels. This colors<br />
can be set, for windows created with createWindow, using the attribute<br />
mask, and setting CWBackPixel and CWBorderPixel with the needed<br />
functions: <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Misc.html#v%3Aset_background_pixel set_background_pixel] <br />
and <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Misc.html#v%3Aset_border_pixel set_border_pixel].<br />
<br />
By the way, setting the border color with this version of<br />
mkUnmanagedWindow is actually useless since the border width is set to<br />
zero. In the next example we will set it to 1.<br />
<br />
Our function needs also the screen now, since we have to retrieve the<br />
default depth and visual.<br />
<br />
We can now rewrite our initial code using the new function now.<br />
<br />
<haskell><br />
<br />
module Main where<br />
import Data.Bits<br />
import Graphics.X11.Xlib<br />
import System.Exit (exitWith, ExitCode(..))<br />
import Control.Concurrent (threadDelay)<br />
<br />
main :: IO ()<br />
main =<br />
do dpy <- openDisplay ""<br />
let dflt = defaultScreen dpy<br />
scr = defaultScreenOfDisplay dpy<br />
rootw <- rootWindow dpy dflt<br />
win <- mkUnmanagedWindow dpy scr rootw 0 0 100 100<br />
setTextProperty dpy win "Hello World" wM_NAME <br />
mapWindow dpy win<br />
sync dpy False<br />
threadDelay (10 * 1000000)<br />
exitWith ExitSuccess<br />
<br />
mkUnmanagedWindow :: Display<br />
-> Screen<br />
-> Window<br />
-> Position<br />
-> Position<br />
-> Dimension<br />
-> Dimension<br />
-> IO Window<br />
mkUnmanagedWindow dpy scr rw x y w h = do<br />
let visual = defaultVisualOfScreen scr<br />
attrmask = cWOverrideRedirect .|. cWBorderPixel .|. cWBackPixel<br />
win <- allocaSetWindowAttributes $ <br />
\attributes -> do<br />
set_override_redirect attributes True<br />
set_background_pixel attributes $ whitePixel dpy (defaultScreen dpy)<br />
set_border_pixel attributes $ blackPixel dpy (defaultScreen dpy)<br />
createWindow dpy rw x y w h 1 (defaultDepthOfScreen scr)<br />
inputOutput visual attrmask attributes <br />
return win<br />
<br />
</haskell><br />
<br />
Ok, let's give it a try. Did you see? Now the window will be placed in<br />
the specified x and y position, with the given dimensions. No Window<br />
Manager decorations, and so, no name displayed.<br />
<br />
===Changing the attributes of an existing window===<br />
<br />
This task requires <br />
[http://www.tronche.com/gui/x/xlib/window/XChangeWindowAttributes.html XChangeWindowAttrbutes()], <br />
implemented only in the darcs version of <br />
[http://hackage.haskell.org/cgi-bin/hackage-scripts/package/X11-extras X11-extras].<br />
<br />
In order to change a window's attributes we just need the window ID in<br />
that specific X server, after that we need to unmap the window first,<br />
and then change its attributes with changeWindowAttributes, the<br />
interface to XChangeWindowAttrbutes() implemented by<br />
[http://darcs.haskell.org/~sjanssen/X11-extras the darcs version of X11-extras].<br />
<br />
Here's the code:<br />
<br />
<haskell><br />
<br />
module Main where<br />
<br />
import Graphics.X11.Xlib<br />
import Graphics.X11.Xlib.Extras<br />
import System.Environment<br />
<br />
usage :: String -> String<br />
usage n = "Usage: " ++ n ++ " manage/unmanage windowID"<br />
<br />
main :: IO ()<br />
main = do<br />
args <- getArgs<br />
pn <- getProgName<br />
let (win,ac) = case args of<br />
[] -> error $ usage pn<br />
w -> case (w !!0) of <br />
"manage" -> (window, False)<br />
"unmanage" -> (window, True)<br />
_ -> error $ usage pn<br />
where window = case (w !! 1) of <br />
[] -> error $ usage pn<br />
w -> read w :: Window<br />
dpy <- openDisplay ""<br />
unmapWindow dpy win<br />
sync dpy False<br />
allocaSetWindowAttributes $<br />
\attributes -> do<br />
set_override_redirect attributes ac<br />
changeWindowAttributes dpy win cWOverrideRedirect attributes<br />
mapWindow dpy win<br />
sync dpy False<br />
<br />
</haskell><br />
<br />
Save it as Unmanage.hs and compile with:<br />
ghc --make Unmanage.hs -o unmanage<br />
<br />
To use it you need to retrieve the window ID with the stand alone utility<br />
xwininfo<br />
<br />
Then you run the above code with:<br />
unmanage unmanage/manage windowID<br />
<br />
to set override_redirect to True or False.<br />
<br />
Obviously the important part of the code is this:<br />
<haskell><br />
dpy <- openDisplay ""<br />
unmapWindow dpy win<br />
sync dpy False<br />
allocaSetWindowAttributes $<br />
\attributes -> do<br />
set_override_redirect attributes ac<br />
changeWindowAttributes dpy win cWOverrideRedirect attributes<br />
mapWindow dpy win<br />
sync dpy False<br />
</haskell><br />
<br />
where we:<br />
# connect to the X server<br />
# unmap the window<br />
# flush the output buffer to have the X server actually unmap the window<br />
# change the attributes with the same procedure we used to set them when creating the window<br />
# map the window again<br />
# flush the output buffer to see the change take effect.<br />
<br />
You can modify this program to change other window's attributes.<br />
<br />
==Colors and color depth==<br />
<br />
So far we have set the window background color as a window attribute.<br />
This is not the most convenient way to set the window background<br />
color: if we need to change it, we must change the window's attribute,<br />
and we have seen that this task requires unmapping the window,<br />
flushing the output with changeWindowAttributes within<br />
changeWindowAttributes, remapping the window and reflushing the output<br />
buffer. Moreover we can do that only we the darcs version of<br />
X11-extras...<br />
<br />
In the following sections we are going to adopt a more efficient way<br />
of setting the window's background color: we will start drawing into<br />
the window. But first we must familiarize with colors and the way the<br />
X server deals with them.<br />
<br />
So far we have set the colors by using some functions to retrieve<br />
their pixel values: blackPixel and whitePixel. These functions take<br />
the display and the default screen and return respectively the pixel<br />
values for the black and the white colors in that screen.<br />
<br />
A color is represented by a 32-bit unsigned integer, called a pixel<br />
value. The elements affecting the pixel representation of a color are:<br />
1. the color depth; 2. the colormap, which is a table containing red,<br />
green, and blue intensity values; 3. the visual type.<br />
<br />
All these elements are specific to a given piece of hardware, and so<br />
our X application must detect them in order to set colors<br />
appropriately for that given hardware.<br />
<br />
The approach we are going to use to accomplish this task is this: we<br />
are going to use named colors, or colors represented by<br />
[http://en.wikipedia.org/wiki/RGB RGB triple], such as "red",<br />
"yellow", or "#FFFFFF", etc; and we are going to translate these<br />
colors into the pixel values appropriate for the screen we are<br />
operating on.<br />
<br />
In order to achieve our goal we are going to use the function <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Color.html#v%3AallocNamedColor allocNamedColor] <br />
which is the interface to the X11 library function <br />
[http://www.tronche.com/gui/x/xlib/color/XAllocNamedColor.html XAllocNamedColor()].<br />
<br />
The type signature of allocNamedColor is:<br />
<br />
<haskell><br />
<br />
allocNamedColor :: Display -> Colormap -> String -> IO (Color, Color)<br />
<br />
</haskell><br />
<br />
That is to say, given a display connection, a color map and a string -<br />
our color representation -, this function will return a tuple with the<br />
closest RGB values provided by the hardware and the exact RGB values,<br />
both encoded in a <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib.html#v%3AColor Haskell Color data type]. <br />
We will use the first approximated value.<br />
<br />
The Color data type has a field name we will use to retrieve the<br />
needed pixel value: <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib.html#v%3Acolor_pixel color_pixel].<br />
<br />
We can now write this helper function:<br />
<br />
<haskell><br />
<br />
initColor :: Display -> String -> IO Pixel<br />
initColor dpy color = do<br />
let colormap = defaultColormap dpy (defaultScreen dpy)<br />
(approx,real) <- allocNamedColor dpy colormap color<br />
return $ color_pixel approx <br />
<br />
</haskell><br />
<br />
To retrieve the colormap of the screen we used <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Display.html#v%3AdefaultColormap defaultColormap], <br />
the interface to the X11 library function <br />
[http://www.tronche.com/gui/x/xlib/display/display-macros.html#DefaultColormap XDefaultColormap()], <br />
which requires the display and the screen, and returns the colormap of that screen.<br />
<br />
We can now rewrite our example using this new approach.<br />
<br />
<haskell><br />
<br />
module Main where<br />
import Data.Bits<br />
import Graphics.X11.Xlib<br />
import System.Exit (exitWith, ExitCode(..))<br />
import Control.Concurrent (threadDelay)<br />
<br />
main :: IO ()<br />
main =<br />
do dpy <- openDisplay ""<br />
let dflt = defaultScreen dpy<br />
scr = defaultScreenOfDisplay dpy<br />
rootw <- rootWindow dpy dflt<br />
win <- mkUnmanagedWindow dpy scr rootw 0 0 100 100<br />
setTextProperty dpy win "Hello World" wM_NAME <br />
mapWindow dpy win<br />
sync dpy False<br />
threadDelay (10 * 1000000)<br />
exitWith ExitSuccess<br />
<br />
mkUnmanagedWindow :: Display<br />
-> Screen<br />
-> Window<br />
-> Position<br />
-> Position<br />
-> Dimension<br />
-> Dimension<br />
-> IO Window<br />
mkUnmanagedWindow dpy scr rw x y w h = do<br />
let visual = defaultVisualOfScreen scr<br />
attrmask = cWOverrideRedirect .|. cWBorderPixel .|. cWBackPixel<br />
background_color <- initColor dpy "red"<br />
border_color <- initColor dpy "black" <br />
win <- allocaSetWindowAttributes $ <br />
\attributes -> do<br />
set_override_redirect attributes True<br />
set_background_pixel attributes background_color<br />
set_border_pixel attributes border_color<br />
createWindow dpy rw x y w h 1 (defaultDepthOfScreen scr)<br />
inputOutput visual attrmask attributes <br />
return win<br />
<br />
<br />
initColor :: Display -> String -> IO Pixel<br />
initColor dpy color = do<br />
let colormap = defaultColormap dpy (defaultScreen dpy)<br />
(apros,real) <- allocNamedColor dpy colormap color<br />
return $ color_pixel apros<br />
<br />
</haskell><br />
<br />
Just give it a try. Now you can also experiment with different colors.<br />
This approach will assure that our application will work no matter the<br />
color depth of the screen we are working on.<br />
<br />
==Drawing in windows==<br />
<br />
The X server provides two objects that can be used to draw something<br />
to: windows and pixmaps.<br />
<br />
In this section we will start drawing into windows.<br />
<br />
We have seen that changing the background color of a window is a<br />
troublesome operation, since the window must be unamapped and<br />
remapped, memory for a foreign structure allocated, and so on.<br />
<br />
Instead, we can use some graphic operations to draw a rectangle over<br />
the window. We will latter manipulate the foreground, visible, color of<br />
this rectangle, that will become the new background of our window.<br />
<br />
We can also use multiple rectangles with different dimension to<br />
decorate our window with a border, for instance.<br />
<br />
Later on we will print some text over these rectangles.<br />
<br />
===Drawing rectangles in a window===<br />
<br />
Citing from<br />
[http://en.wikipedia.org/wiki/X_Window_System_core_protocol#Graphic_contexts_and_fonts Wikipedia]:<br />
<br />
<blockquote><br />
The client can request a number of graphic operations, such clearing<br />
an area, copying an area into another, drawing points, lines,<br />
rectangles, and text. Beside clearing, all operations are possible on<br />
all drawables, both windows and pixmaps.<br />
<br />
Most requests for graphic operations include a graphic context, which<br />
is a structure that contains the parameters of the graphic operations.<br />
A graphic context includes the foreground color, the background color,<br />
the font of text, and other graphic parameters. When requesting a<br />
graphic operation, the client includes a graphic context.<br />
</blockquote> <br />
<br />
In other words, as for setting window's attribute, we must use a<br />
foreign C structure to set parameters for graphic operations, and then<br />
we will feed this structure to the <br />
[http://www.tronche.com/gui/x/xlib/graphics/ functions] <br />
that will perform these graphic operations.<br />
<br />
We one difference: instead of operating within a function that<br />
allocates memory and creates a pointer to the foreign structure, now<br />
we have to explicitally create the Graphic Context, and free it after<br />
having used it, with <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Context.html#v%3AcreateGC createGC], <br />
the interface to <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Context.html#v%3AcreateGC XCreateGC], <br />
and<br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Context.html#v%3AfreeGC freeGC], <br />
the interface to <br />
[http://www.tronche.com/gui/x/xlib/GC/XFreeGC.html XFreeGC].<br />
<br />
Be careful: if you create a graphic con without freeing it after use,<br />
you are going to end up with a noticeable memory leak!<br />
<br />
The specific graphic functions we are going to need for drawing a<br />
rectangle into our window are:<br />
<br />
# [http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Context.html#v%3AsetForeground setForegrond] the interface to [http://www.tronche.com/gui/x/xlib/GC/convenience-functions/XSetForeground.html XSetForegroung]<br />
# [http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Context.html#v%3AsetBackground setBackground] the interface to [http://www.tronche.com/gui/x/xlib/GC/convenience-functions/XSetBackground.html XSetBackground]<br />
# [http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Misc.html#v%3AfillRectangle fillRectangle] the interface to [http://www.tronche.com/gui/x/xlib/graphics/filling-areas/XFillRectangle.html XFillRectangle]<br />
<br />
The first two functions are needed to set the parameters in the<br />
[http://www.tronche.com/gui/x/xlib/GC/manipulating.html Graphic Context]. <br />
The third one will use this GC for filling a rectangle on the<br />
specified window. Just have a look to their type signatures:<br />
<br />
<haskell><br />
<br />
setForeground :: Display -> GC -> Pixel -> IO ()<br />
setBackground :: Display -> GC -> Pixel -> IO ()<br />
fillRectangle :: Display -> Drawable -> GC -> Position -> Position -> Dimension -> Dimension -> IO ()<br />
<br />
</haskell><br />
<br />
Ok, this is the function that we will be using for drawing into a<br />
window:<br />
<br />
<haskell><br />
<br />
drawInWin :: Display -> Window -> IO ()<br />
drawInWin dpy win = do<br />
fgcolor <- initColor dpy "blue"<br />
gc <- createGC dpy win<br />
setForeground dpy gc fgcolor<br />
fillRectangle dpy win gc 0 0 100 100<br />
freeGC dpy gc<br />
<br />
</haskell><br />
<br />
This will just fill our window with a rectangle at (0, 0) (x, y)<br />
coordinates (relatives to the window's internal border), with the same<br />
dimensions of our window.<br />
<br />
Obviously we can play a bit with rectangles. This version, for<br />
instance, will draw 2 rectangles to simulate a blu rectangle with a<br />
green border, two pixels width:<br />
<br />
<haskell><br />
<br />
drawInWin :: Display -> Window -> IO ()<br />
drawInWin dpy win = do<br />
bgcolor <- initColor dpy "green"<br />
fgcolor <- initColor dpy "blue"<br />
gc <- createGC dpy win<br />
setForeground dpy gc bgcolor<br />
fillRectangle dpy win gc 0 0 100 100<br />
setForeground dpy gc fgcolor<br />
fillRectangle dpy win gc 2 2 96 96<br />
freeGC dpy gc<br />
<br />
</haskell><br />
<br />
You can use this function on a mapped window. This is our original<br />
example rewritten with this new approach:<br />
<br />
<haskell><br />
<br />
module Main where<br />
import Data.Bits<br />
import Graphics.X11.Xlib<br />
import System.Exit (exitWith, ExitCode(..))<br />
import Control.Concurrent (threadDelay)<br />
<br />
main :: IO ()<br />
main =<br />
do dpy <- openDisplay ""<br />
let dflt = defaultScreen dpy<br />
scr = defaultScreenOfDisplay dpy<br />
rootw <- rootWindow dpy dflt<br />
win <- mkUnmanagedWindow dpy scr rootw 0 0 100 100<br />
setTextProperty dpy win "Hello World" wM_NAME <br />
mapWindow dpy win<br />
drawInWin dpy win<br />
sync dpy False<br />
threadDelay (10 * 1000000)<br />
exitWith ExitSuccess<br />
<br />
drawInWin :: Display -> Window -> IO ()<br />
drawInWin dpy win = do<br />
bgcolor <- initColor dpy "green"<br />
fgcolor <- initColor dpy "blue"<br />
gc <- createGC dpy win<br />
setForeground dpy gc bgcolor<br />
fillRectangle dpy win gc 0 0 100 100<br />
setForeground dpy gc fgcolor<br />
fillRectangle dpy win gc 2 2 96 96<br />
freeGC dpy gc<br />
<br />
mkUnmanagedWindow :: Display<br />
-> Screen<br />
-> Window<br />
-> Position<br />
-> Position<br />
-> Dimension<br />
-> Dimension<br />
-> IO Window<br />
mkUnmanagedWindow dpy scr rw x y w h = do<br />
let visual = defaultVisualOfScreen scr<br />
win <- allocaSetWindowAttributes $ <br />
\attributes -> do<br />
set_override_redirect attributes True<br />
createWindow dpy rw x y w h 0 (defaultDepthOfScreen scr)<br />
inputOutput visual cWOverrideRedirect attributes <br />
return win<br />
<br />
<br />
initColor :: Display -> String -> IO Pixel<br />
initColor dpy color = do<br />
<br />
</haskell><br />
<br />
As you see, now mkUnmanagedWindow sets a null border width and does<br />
not set any background color. Everything is easily done with<br />
rectangles.<br />
<br />
===Printing a string===<br />
<br />
Printing a string to a window requires operating with another foreign<br />
C structure, the <br />
[http://www.tronche.com/gui/x/xlib/graphics/font-metrics/ XFontStruct], <br />
which contains all of the information regarding the metrics of font<br />
that the X server will use to display our string.<br />
<br />
This structure will be used to perform some computations that are<br />
required for the correct placement of the text in the window.<br />
<br />
As we have seen with the window's attributes and the Graphic Context,<br />
we need a function that returns a pointer to this foreign structure,<br />
pointer that must be freed after using it.<br />
<br />
A pointer to the XFontStruct is returned by <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Font.html#v%3AloadQueryFont loadQueryFont], <br />
the interface to the X11 library function <br />
[http://www.tronche.com/gui/x/xlib/graphics/font-metrics/XLoadQueryFont.html XLoadQueryFont()].<br />
<br />
XLoadQueryFont, which requires the X connection and the font name,<br />
will perform two distinct operations: load the needed font and return<br />
its id<br />
(performed by [http://www.tronche.com/gui/x/xlib/graphics/font-metrics/XLoadFont.html XLoadFont()] <br />
which doesn't have a Haskell interface) and query the font to retrieve the XFontStruct <br />
(performed by [http://www.tronche.com/gui/x/xlib/graphics/font-metrics/XQueryFont.html XQueryFont] <br />
which does have a Haskell interface:<br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Font.html#v%3AqueryFont queryFont]).<br />
<br />
The XFontStruct is needed by <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Font.html#v%3AtextExtents textExtents], <br />
the interface to <br />
[http://www.tronche.com/gui/x/xlib/graphics/font-metrics/XTextExtents.html XTexteExtent()], <br />
and <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Font.html#v%3AtextWidth textWidth], <br />
the interface to <br />
[http://www.tronche.com/gui/x/xlib/graphics/font-metrics/XTextWidth.html XTextWidth()].<br />
<br />
These are their type signatures.<br />
<br />
<haskell><br />
<br />
textExtents :: FontStruct -> String -> (FontDirection, Int32, Int32, CharStruct)<br />
textWidth :: FontStruct -> String -> Int32<br />
<br />
</haskell><br />
<br />
Given the FontStruct and the string to be printed, these functions<br />
will provide some valuable information. The values returned by the<br />
first one are related to font direction and vertical placement, while<br />
the second one will return the total width of the string to be printed<br />
with that specific font.<br />
<br />
This information can be used with the graphic function that will<br />
actually draw the text on the window: <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Misc.html#v%3AdrawImageString drawImageString], <br />
the interface to <br />
[http://www.tronche.com/gui/x/xlib/graphics/drawing-text/XDrawImageString.html XDrawImageString].<br />
<br />
There are other version of this string, <br />
[http://www.tronche.com/gui/x/xlib/graphics/drawing-text/XDrawText.html XDrawText()] <br />
and <br />
[http://www.tronche.com/gui/x/xlib/graphics/drawing-text/XDrawText16.html XDrawText16()] <br />
for 16-bit characters.<br />
<br />
We are going to use the first one because it will also use the<br />
foreground pixel set in the Graphic Context.<br />
<br />
It's type signature is:<br />
<br />
<haskell><br />
<br />
drawImageString :: Display -> Drawable -> GC -> Position -> Position -> String -> IO ()<br />
<br />
</haskell><br />
<br />
Finally we must remember to free the FontStruct with <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Font.html#v%3AfreeFont freeFont] <br />
the interface to <br />
[http://www.tronche.com/gui/x/xlib/graphics/font-metrics/XFreeFont.html XFreeFont].<br />
<br />
We can now write our function to print a string on a window, but first<br />
we need to make some small modifications to our darwInWin function,<br />
that will now take a string and will load and free the needed<br />
FontStruct to be passed to the new printString function:<br />
<br />
<haskell><br />
<br />
drawInWin :: Display -> Window -> String -> IO ()<br />
drawInWin dpy win str = do<br />
bgcolor <- initColor dpy "green"<br />
fgcolor <- initColor dpy "blue"<br />
gc <- createGC dpy win<br />
fontStruc <- loadQueryFont dpy "-misc-fixed-*-*-*-*-10-*-*-*-*-*-*-*"<br />
setForeground dpy gc bgcolor<br />
fillRectangle dpy win gc 0 0 200 100<br />
setForeground dpy gc fgcolor<br />
fillRectangle dpy win gc 2 2 196 96<br />
printString dpy win gc fontStruc str<br />
freeGC dpy gc<br />
freeFont dpy fontStruc<br />
<br />
</haskell><br />
<br />
Here we are loading the "misc-fixed" font. You can select different<br />
fonts with the standalone utility:<br />
xfontsel<br />
<br />
As you see the FontStruct retrieved by loadQueryFont is used by<br />
printString and then freed.<br />
<br />
So, let's look printString:<br />
<br />
<br />
<haskell><br />
<br />
printString :: Display <br />
-> Drawable <br />
-> GC<br />
-> FontStruct<br />
-> String<br />
-> IO ()<br />
printString dpy d gc fontst str =<br />
do let strLen = textWidth fontst str<br />
(_,asc,_,_) = textExtents fontst str<br />
valign = (100 + fromIntegral asc) `div` 2<br />
remWidth = 200 - strLen<br />
offset = remWidth `div` 2<br />
fgcolor <- initColor dpy "white"<br />
bgcolor <- initColor dpy "blue"<br />
setForeground dpy gc fgcolor<br />
setBackground dpy gc bgcolor<br />
drawImageString dpy d gc offset valign str<br />
<br />
</haskell><br />
<br />
In the "let" part we use textWidth and textExtents to set vertical and<br />
horizontal alignment: this is done by calculating the x and y<br />
coordinates for drawImageString. In this example text will be<br />
vertically and horizontally centered (take into account that I have<br />
also enlarged the window, whose width now is 200 pixels).<br />
<br />
For a reference of the meaning of font ascent and descent, and the<br />
origins of the rectangle drawn by drawImageString read the par. 8.6<br />
([http://www.tronche.com/gui/x/xlib/graphics/drawing-text/ Drawing Text]) <br />
of the <br />
[http://www.tronche.com/gui/x/xlib/ The Xlib Manual].<br />
<br />
You may notice that printString takes a <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Types.html#t%3ADrawable Drawable], <br />
which can be either a window or a pixmap (see below).<br />
<br />
We can now rewrite our example and finally see some text printed in<br />
our window:<br />
<br />
<haskell><br />
<br />
module Main where<br />
import Data.Bits<br />
import Graphics.X11.Xlib<br />
import System.Exit (exitWith, ExitCode(..))<br />
import System.Time<br />
import Control.Concurrent (threadDelay)<br />
<br />
main :: IO ()<br />
main =<br />
do dpy <- openDisplay ""<br />
let dflt = defaultScreen dpy<br />
scr = defaultScreenOfDisplay dpy<br />
rootw <- rootWindow dpy dflt<br />
win <- mkUnmanagedWindow dpy scr rootw 0 0 200 100<br />
setTextProperty dpy win "The Clock" wM_NAME <br />
mapWindow dpy win<br />
drawInWin dpy win =<< date<br />
sync dpy False<br />
threadDelay (10 * 1000000)<br />
exitWith ExitSuccess<br />
<br />
date :: IO String<br />
date = do <br />
t <- getClockTime<br />
return $ calendarTimeToString . toUTCTime $ t <br />
<br />
drawInWin :: Display -> Window -> String -> IO ()<br />
drawInWin dpy win str = do<br />
bgcolor <- initColor dpy "green"<br />
fgcolor <- initColor dpy "blue"<br />
gc <- createGC dpy win<br />
fontStruc <- loadQueryFont dpy "-misc-fixed-*-*-*-*-10-*-*-*-*-*-*-*"<br />
setForeground dpy gc bgcolor<br />
fillRectangle dpy win gc 0 0 200 100<br />
setForeground dpy gc fgcolor<br />
fillRectangle dpy win gc 2 2 196 96<br />
printString dpy win gc fontStruc str<br />
freeGC dpy gc<br />
freeFont dpy fontStruc<br />
<br />
printString :: Display <br />
-> Drawable <br />
-> GC<br />
-> FontStruct<br />
-> String<br />
-> IO ()<br />
printString dpy d gc fontst str =<br />
do let strLen = textWidth fontst str<br />
(_,asc,_,_) = textExtents fontst str<br />
valign = (100 + fromIntegral asc) `div` 2<br />
remWidth = 200 - strLen<br />
offset = remWidth `div` 2<br />
fgcolor <- initColor dpy "white"<br />
bgcolor <- initColor dpy "blue"<br />
setForeground dpy gc fgcolor<br />
setBackground dpy gc bgcolor<br />
drawImageString dpy d gc offset valign str<br />
<br />
mkUnmanagedWindow :: Display<br />
-> Screen<br />
-> Window<br />
-> Position<br />
-> Position<br />
-> Dimension<br />
-> Dimension<br />
-> IO Window<br />
mkUnmanagedWindow dpy scr rw x y w h = do<br />
let visual = defaultVisualOfScreen scr<br />
win <- allocaSetWindowAttributes $ <br />
\attributes -> do<br />
set_override_redirect attributes True<br />
createWindow dpy rw x y w h 0 (defaultDepthOfScreen scr)<br />
inputOutput visual cWOverrideRedirect attributes <br />
return win<br />
<br />
<br />
initColor :: Display -> String -> IO Pixel<br />
initColor dpy color = do<br />
let colormap = defaultColormap dpy (defaultScreen dpy)<br />
(apros,real) <- allocNamedColor dpy colormap color<br />
return $ color_pixel apros<br />
<br />
</haskell><br />
<br />
Since we are going to display the system time, I already added a<br />
"date" function and increased to width of our window. <br />
<br />
Just give it a try. We are almost there. It's a clock, after all.<br />
<br />
==Updating a window==<br />
<br />
If you do not believe that now we have a system clock, just change the<br />
main function of the above example with the following two functions and<br />
try yourself:<br />
<br />
<haskell><br />
<br />
main :: IO ()<br />
main = do <br />
dpy <- openDisplay ""<br />
let dflt = defaultScreen dpy<br />
scr = defaultScreenOfDisplay dpy<br />
rootw <- rootWindow dpy dflt<br />
win <- mkUnmanagedWindow dpy scr rootw 0 0 200 100<br />
setTextProperty dpy win "The Clock" wM_NAME <br />
mapWindow dpy win<br />
updateWin dpy win<br />
<br />
updateWin :: Display -> Window -> IO ()<br />
updateWin dpy win = do<br />
drawInWin dpy win =<< date<br />
sync dpy False<br />
threadDelay (1 * 1000000)<br />
updateWin dpy win<br />
<br />
</haskell><br />
<br />
This piece of code just adds the eternal recursive loop and, within<br />
this loop, reduces the thread block to 1 second. That's it.<br />
<br />
Every second our window will be updated - redrawn.<br />
<br />
Now, if you let the clock run for a while, you will notice that<br />
sometimes, during an update, the window sort of flickers.<br />
<br />
This is due to the fact that we are drawing directly over the window.<br />
We need to adopt a better technique: we need to write to a pixmap<br />
first, and then copy the pixmap over the window.<br />
<br />
Citing from<br />
[http://en.wikipedia.org/wiki/X_Window_System_core_protocol#Pixmaps_and_drawables Wikipedia]:<br />
<br />
<blockquote> <br />
«A pixmap is a region of memory that can be used for<br />
drawing. Contrary to windows, the contents of pixmaps are not<br />
automatically shown on the screen. However, the content of a pixmap<br />
(or a part of it) can be transferred to a window and vice versa. This<br />
allows for techniques such as <br />
[http://en.wikipedia.org/wiki/Double_buffering double buffering]. <br />
Most of the graphical<br />
operations that can be done on windows can also be done on pixmaps.<br />
Windows and pixmaps are collectively named drawables, and their<br />
content data resides on the server.» <br />
</blockquote><br />
<br />
This is not very difficult, and requires a very small change of our<br />
drawInWin function.<br />
<br />
In order to create the pixmap we will use <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Misc.html#v%3AcreatePixmap createPixmap], <br />
the interface to <br />
[http://www.tronche.com/gui/x/xlib/pixmap-and-cursor/XCreatePixmap.htm XCreatePixmap()], <br />
which takes the display connection, the drawable upon which the pixmap<br />
is created, the width, the height, and the depth of the screen.<br />
<br />
We will then use <br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Misc.html#v%3AcopyArea copyArea], <br />
the interface to <br />
[http://www.tronche.com/gui/x/xlib/graphics/XCopyArea.html XCopyArea], <br />
to copy the pixmap over the window.<br />
<br />
This is the copyArea type signature:<br />
<br />
<haskell><br />
<br />
copyArea :: Display <br />
-> Drawable -> Drawable <br />
-> GC <br />
-> Position -> Position <br />
-> Dimension -> Dimension <br />
-> Position -> Position <br />
-> IO ()<br />
<br />
</haskell><br />
<br />
that is to say:<br />
# the display connection<br />
# the origin and the destination drawables (our pixmap and our window respectively)<br />
# the x and y coordinates relative to the origin drawable upper left corner<br />
# the width and the height of the area the be copied<br />
# the x and y coordinates relative to the upper left corner of the destination drawable where the copied area must be placed<br />
<br />
And we will eventually free the pixmap with<br />
[http://hackage.haskell.org/packages/archive/X11/1.2.2/doc/html/Graphics-X11-Xlib-Misc.html#v%3AfreePixmap freePixmap], <br />
the interface to <br />
[http://www.tronche.com/gui/x/xlib/pixmap-and-cursor/XFreePixmap.html XFreePixmap].<br />
<br />
Since our printString function may accept either a window or a pixmap,<br />
they both are drawables, all we need to do is to change drawInWin<br />
accordingly:<br />
<br />
<haskell><br />
<br />
drawInWin :: Display -> Window -> String ->IO ()<br />
drawInWin dpy win str = do<br />
bgcolor <- initColor dpy "green"<br />
fgcolor <- initColor dpy "blue"<br />
gc <- createGC dpy win<br />
fontStruc <- loadQueryFont dpy "-misc-fixed-*-*-*-*-10-*-*-*-*-*-*-*"<br />
p <- createPixmap dpy win 200 100 (defaultDepthOfScreen (defaultScreenOfDisplay dpy))<br />
setForeground dpy gc bgcolor<br />
fillRectangle dpy p gc 0 0 200 100<br />
setForeground dpy gc fgcolor<br />
fillRectangle dpy p gc 2 2 196 96<br />
printString dpy p gc fontStruc str<br />
copyArea dpy p win gc 0 0 200 100 0 0<br />
freeGC dpy gc<br />
freeFont dpy fontStruc<br />
freePixmap dpy p<br />
<br />
</haskell><br />
<br />
Now, all graphic functions take now "p" and not "win". After copyArea<br />
everything is freed.<br />
<br />
Our clock:<br />
<br />
<haskell><br />
<br />
module Main where<br />
import Data.Bits<br />
import Graphics.X11.Xlib<br />
import System.Exit (exitWith, ExitCode(..))<br />
import System.Time<br />
import Control.Concurrent (threadDelay)<br />
<br />
main :: IO ()<br />
main = do <br />
dpy <- openDisplay ""<br />
let dflt = defaultScreen dpy<br />
scr = defaultScreenOfDisplay dpy<br />
rootw <- rootWindow dpy dflt<br />
win <- mkUnmanagedWindow dpy scr rootw 0 0 200 100<br />
setTextProperty dpy win "Hello World - The Clock" wM_NAME <br />
mapWindow dpy win<br />
updateWin dpy win<br />
<br />
updateWin :: Display -> Window -> IO ()<br />
updateWin dpy win = do<br />
drawInWin dpy win =<< date<br />
sync dpy False<br />
threadDelay (1 * 1000000)<br />
updateWin dpy win<br />
<br />
date :: IO String<br />
date = do <br />
t <- getClockTime<br />
return $ calendarTimeToString . toUTCTime $ t <br />
<br />
drawInWin :: Display -> Window -> String ->IO ()<br />
drawInWin dpy win str = do<br />
bgcolor <- initColor dpy "green"<br />
fgcolor <- initColor dpy "blue"<br />
gc <- createGC dpy win<br />
fontStruc <- loadQueryFont dpy "-misc-fixed-*-*-*-*-10-*-*-*-*-*-*-*"<br />
p <- createPixmap dpy win 200 100 (defaultDepthOfScreen (defaultScreenOfDisplay dpy))<br />
setForeground dpy gc bgcolor<br />
fillRectangle dpy p gc 0 0 200 100<br />
setForeground dpy gc fgcolor<br />
fillRectangle dpy p gc 2 2 196 96<br />
printString dpy p gc fontStruc str<br />
copyArea dpy p win gc 0 0 200 100 0 0<br />
freeGC dpy gc<br />
freeFont dpy fontStruc<br />
freePixmap dpy p<br />
<br />
<br />
printString :: Display <br />
-> Drawable <br />
-> GC<br />
-> FontStruct<br />
-> String<br />
-> IO ()<br />
printString dpy d gc fontst str =<br />
do let strLen = textWidth fontst str<br />
(_,asc,_,_) = textExtents fontst str<br />
valign = (100 + fromIntegral asc) `div` 2<br />
remWidth = 200 - strLen<br />
offset = remWidth `div` 2<br />
fgcolor <- initColor dpy "white"<br />
bgcolor <- initColor dpy "blue"<br />
setForeground dpy gc fgcolor<br />
setBackground dpy gc bgcolor<br />
drawImageString dpy d gc offset valign str<br />
<br />
mkUnmanagedWindow :: Display<br />
-> Screen<br />
-> Window<br />
-> Position<br />
-> Position<br />
-> Dimension<br />
-> Dimension<br />
-> IO Window<br />
mkUnmanagedWindow dpy scr rw x y w h = do<br />
let visual = defaultVisualOfScreen scr<br />
win <- allocaSetWindowAttributes $ <br />
\attributes -> do<br />
set_override_redirect attributes True<br />
createWindow dpy rw x y w h 0 (defaultDepthOfScreen scr)<br />
inputOutput visual cWOverrideRedirect attributes <br />
return win<br />
<br />
<br />
initColor :: Display -> String -> IO Pixel<br />
initColor dpy color = do<br />
let colormap = defaultColormap dpy (defaultScreen dpy)<br />
(apros,real) <- allocNamedColor dpy colormap color<br />
return $ color_pixel apros<br />
<br />
</haskell><br />
<br />
<br />
==Dealing with XEvents==<br />
<br />
Now try this.<br />
<br />
In updateWin set threadDelay to something like:<br />
<br />
<haskell><br />
<br />
threadDelay (60 * 1000000)<br />
<br />
</haskell><br />
<br />
Run the clock, switch to a console (with Alt+Ctrl+F1) and come back to<br />
the X server where the clock is running.<br />
<br />
'''To be continued ...'''<br />
<br />
Two approaches<br />
<br />
- [[User:AndreaRossato|Andrea Rossato]]<br />
<br />
[[Category:Tutorials]]</div>BrettGileshttps://wiki.haskell.org/index.php?title=X_Window_Programming_in_Haskell&diff=14584X Window Programming in Haskell2007-07-22T17:41:08Z<p>BrettGiles: X Window Programming in Haskell moved to X window programming: Page case guidelines, "In Haskell" redundant on this site, as per guidelines.</p>
<hr />
<div>#redirect [[X window programming]]</div>BrettGiles