<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	
	>
<channel>
	<title>Comments on: Notions of purity in Haskell</title>
	<atom:link href="http://conal.net/blog/posts/notions-of-purity-in-haskell/feed" rel="self" type="application/rss+xml" />
	<link>http://conal.net/blog/posts/notions-of-purity-in-haskell</link>
	<description>Inspirations &#38; experiments, mainly about denotative/functional programming in Haskell</description>
	<lastBuildDate>Sat, 26 Sep 2020 21:06:12 +0000</lastBuildDate>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=4.1.17</generator>
	<item>
		<title>By: Irene Knapp</title>
		<link>http://conal.net/blog/posts/notions-of-purity-in-haskell#comment-449</link>
		<dc:creator><![CDATA[Irene Knapp]]></dc:creator>
		<pubDate>Wed, 13 Nov 2013 20:01:24 +0000</pubDate>
		<guid isPermaLink="false">http://conal.net/blog/?p=86#comment-449</guid>
		<description><![CDATA[&lt;p&gt;I do cherish these principles; they are good ones.  Just for the record!&lt;/p&gt;
]]></description>
		<content:encoded><![CDATA[<p>I do cherish these principles; they are good ones.  Just for the record!</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Tommy Thorn</title>
		<link>http://conal.net/blog/posts/notions-of-purity-in-haskell#comment-448</link>
		<dc:creator><![CDATA[Tommy Thorn]]></dc:creator>
		<pubDate>Sun, 02 Jun 2013 21:58:53 +0000</pubDate>
		<guid isPermaLink="false">http://conal.net/blog/?p=86#comment-448</guid>
		<description><![CDATA[&lt;p&gt;Thank you for expressing more eloquently what I can&#039;t mention without risking a
nerd-rage.&lt;/p&gt;

&lt;p&gt;I was pointed to your article from haskell-cafe where a real world instance of
the horrible Int semantics resulted in the same program mysteriously behaving
differently on two different platforms.&lt;/p&gt;

&lt;p&gt;My only &quot;contribution&quot; here is to question the premise that led The Committee to
give Int the silent overflowing semantics.  With modern compiler technology and
modern hardware, trapping overflows doesn&#039;t necessarily come with a larger performance
overhead.  A conditional branch on the overflow from an add is nearly zero cost as it
predicts perfectly and can be issued in parallel with all other instructions.  Some
architectures, eg. SPARC, even have overflow checking add/sub variants with zero
overhead.  Not to mention that for many instances it&#039;s trivial to see that overflow
can&#039;t happen.&lt;/p&gt;
]]></description>
		<content:encoded><![CDATA[<p>Thank you for expressing more eloquently what I can&#8217;t mention without risking a
nerd-rage.</p>

<p>I was pointed to your article from haskell-cafe where a real world instance of
the horrible Int semantics resulted in the same program mysteriously behaving
differently on two different platforms.</p>

<p>My only &#8220;contribution&#8221; here is to question the premise that led The Committee to
give Int the silent overflowing semantics.  With modern compiler technology and
modern hardware, trapping overflows doesn&#8217;t necessarily come with a larger performance
overhead.  A conditional branch on the overflow from an add is nearly zero cost as it
predicts perfectly and can be issued in parallel with all other instructions.  Some
architectures, eg. SPARC, even have overflow checking add/sub variants with zero
overhead.  Not to mention that for many instances it&#8217;s trivial to see that overflow
can&#8217;t happen.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Conal Elliott &#187; Blog Archive &#187; Lazier functional programming, part 1</title>
		<link>http://conal.net/blog/posts/notions-of-purity-in-haskell#comment-447</link>
		<dc:creator><![CDATA[Conal Elliott &#187; Blog Archive &#187; Lazier functional programming, part 1]]></dc:creator>
		<pubDate>Mon, 20 Dec 2010 20:52:32 +0000</pubDate>
		<guid isPermaLink="false">http://conal.net/blog/?p=86#comment-447</guid>
		<description><![CDATA[&lt;p&gt;[...] semantics, amenable to various implementations. (Haskell falls somewhat short, as explained in Notions of purity in Haskell.) Sadly, I don&#8217;t know a pleasant comparative form to mean &#8220;less strict&#8221;, so [...]&lt;/p&gt;
]]></description>
		<content:encoded><![CDATA[<p>[&#8230;] semantics, amenable to various implementations. (Haskell falls somewhat short, as explained in Notions of purity in Haskell.) Sadly, I don&#8217;t know a pleasant comparative form to mean &#8220;less strict&#8221;, so [&#8230;]</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: conal</title>
		<link>http://conal.net/blog/posts/notions-of-purity-in-haskell#comment-446</link>
		<dc:creator><![CDATA[conal]]></dc:creator>
		<pubDate>Mon, 22 Jun 2009 16:01:44 +0000</pubDate>
		<guid isPermaLink="false">http://conal.net/blog/?p=86#comment-446</guid>
		<description><![CDATA[&lt;p&gt;Hi Paul,&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;From your original post, you seemed to be saying: &quot;I don&#039;t like System.Info.os :: String&quot; since that violates (the soul of) RT. &lt;em&gt;[...]&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I think I see part of the communication gap here: you thought my post was talking about referential transparency.
Instead, I was shifting the conversation away from a focus on RT and onto two other principles.
With the first one (&quot;the value of a closed expression ... depends solely on the expression itself&quot;), I made a passing nod to RT, accidentally opening the door to confusion.
The second one, which is &quot;even more fundamental to me&quot;, is that &lt;em&gt;types have meanings&lt;/em&gt;, and the meaning of an expression belongs to the meaning of type of that expression.&lt;/p&gt;

&lt;p&gt;One reason I&#039;d like to reframe these discussions in terms other than RT is that I repeatedly see RT discussions get terribly muddled.
And for me, the definitions of RT are technical and without heart.
I get a lot more clarity and oomph out of the principles I&#039;ve stated in this blog post.&lt;/p&gt;

&lt;p&gt;Here&#039;s a more accurate reading of what I was trying to convey: &quot;I don&#039;t like System.Info.os :: String since that typing violates these two principles that are at the heart of what I love about functional programming.  And, by the way, those principles are at the heart of RT for me as well.&quot;  Because there&#039;s so much confusion about RT, and it&#039;s such a technical/lifeless notion, I&#039;m offering a hopefully-more-fruitful alternative to RT as a framework for discussing notions of purity.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Since I think we might be talking past each other, at this point I think we might be better hashing this out over IRC sometime. :) Btw, I&#039;m enjoying this discussion and I think it&#039;s all very interesting!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I&#039;m delighted &amp; relieved to hear you&#039;re enjoying the discussion.  It&#039;s so hard to tell without the usual non-verbal cues, so thanks for letting me know.  I&#039;ll be happy to chat more on IRC.&lt;/p&gt;
]]></description>
		<content:encoded><![CDATA[<p>Hi Paul,</p>

<blockquote>
  <p>From your original post, you seemed to be saying: &#8220;I don&#8217;t like System.Info.os :: String&#8221; since that violates (the soul of) RT. <em>[&#8230;]</em></p>
</blockquote>

<p>I think I see part of the communication gap here: you thought my post was talking about referential transparency.
Instead, I was shifting the conversation away from a focus on RT and onto two other principles.
With the first one (&#8220;the value of a closed expression &#8230; depends solely on the expression itself&#8221;), I made a passing nod to RT, accidentally opening the door to confusion.
The second one, which is &#8220;even more fundamental to me&#8221;, is that <em>types have meanings</em>, and the meaning of an expression belongs to the meaning of type of that expression.</p>

<p>One reason I&#8217;d like to reframe these discussions in terms other than RT is that I repeatedly see RT discussions get terribly muddled.
And for me, the definitions of RT are technical and without heart.
I get a lot more clarity and oomph out of the principles I&#8217;ve stated in this blog post.</p>

<p>Here&#8217;s a more accurate reading of what I was trying to convey: &#8220;I don&#8217;t like System.Info.os :: String since that typing violates these two principles that are at the heart of what I love about functional programming.  And, by the way, those principles are at the heart of RT for me as well.&#8221;  Because there&#8217;s so much confusion about RT, and it&#8217;s such a technical/lifeless notion, I&#8217;m offering a hopefully-more-fruitful alternative to RT as a framework for discussing notions of purity.</p>

<blockquote>
  <p>Since I think we might be talking past each other, at this point I think we might be better hashing this out over IRC sometime. <img src="http://conal.net/blog/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /> Btw, I&#8217;m enjoying this discussion and I think it&#8217;s all very interesting!</p>
</blockquote>

<p>I&#8217;m delighted &amp; relieved to hear you&#8217;re enjoying the discussion.  It&#8217;s so hard to tell without the usual non-verbal cues, so thanks for letting me know.  I&#8217;ll be happy to chat more on IRC.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Paul Chiusano</title>
		<link>http://conal.net/blog/posts/notions-of-purity-in-haskell#comment-445</link>
		<dc:creator><![CDATA[Paul Chiusano]]></dc:creator>
		<pubDate>Mon, 22 Jun 2009 05:05:03 +0000</pubDate>
		<guid isPermaLink="false">http://conal.net/blog/?p=86#comment-445</guid>
		<description><![CDATA[&lt;p&gt;Conal,&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;First, I’m picking up something of a bait-and-switch going on here (unintentional, I presume). I didn’t say that getStr is RT (referentially transparent), nor that I was giving a definition of RT.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ok, maybe I am confused here. From your original post, you seemed to be saying: &quot;I don&#039;t like System.Info.os :: String&quot; since that violates (the soul of) RT. Then I suggested that making its type IO String doesn&#039;t seem to fix anything, also that according to (what I thought was) your definition of RT, getStr was not RT either. From your response I got the (erroneous?) impression that you thought that yes, if we make Info.os :: IO String then we&#039;re RT. Likewise for getStr.&lt;/p&gt;

&lt;p&gt;Since I think we might be talking past each other, at this point I think we might be better hashing this out over IRC sometime. :) Btw, I&#039;m enjoying this discussion and I think it&#039;s all very interesting!&lt;/p&gt;
]]></description>
		<content:encoded><![CDATA[<p>Conal,</p>

<blockquote>
  <p>First, I’m picking up something of a bait-and-switch going on here (unintentional, I presume). I didn’t say that getStr is RT (referentially transparent), nor that I was giving a definition of RT.</p>
</blockquote>

<p>Ok, maybe I am confused here. From your original post, you seemed to be saying: &#8220;I don&#8217;t like System.Info.os :: String&#8221; since that violates (the soul of) RT. Then I suggested that making its type IO String doesn&#8217;t seem to fix anything, also that according to (what I thought was) your definition of RT, getStr was not RT either. From your response I got the (erroneous?) impression that you thought that yes, if we make Info.os :: IO String then we&#8217;re RT. Likewise for getStr.</p>

<p>Since I think we might be talking past each other, at this point I think we might be better hashing this out over IRC sometime. <img src="http://conal.net/blog/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /> Btw, I&#8217;m enjoying this discussion and I think it&#8217;s all very interesting!</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: conal</title>
		<link>http://conal.net/blog/posts/notions-of-purity-in-haskell#comment-444</link>
		<dc:creator><![CDATA[conal]]></dc:creator>
		<pubDate>Mon, 22 Jun 2009 03:07:58 +0000</pubDate>
		<guid isPermaLink="false">http://conal.net/blog/?p=86#comment-444</guid>
		<description><![CDATA[&lt;p&gt;Thanks for the remarks, Luke.  There are a few different definitions of RT floating around.  I see what you mean that your particular definition doesn&#039;t apply in the presence of primitives.  So I guess I prefer the one about replacing subexpressions with other expressions having the same meaning.  It applies with types that have precise semantics, though not yet IO (that I know of).&lt;/p&gt;
]]></description>
		<content:encoded><![CDATA[<p>Thanks for the remarks, Luke.  There are a few different definitions of RT floating around.  I see what you mean that your particular definition doesn&#8217;t apply in the presence of primitives.  So I guess I prefer the one about replacing subexpressions with other expressions having the same meaning.  It applies with types that have precise semantics, though not yet IO (that I know of).</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Luke Palmer</title>
		<link>http://conal.net/blog/posts/notions-of-purity-in-haskell#comment-443</link>
		<dc:creator><![CDATA[Luke Palmer]]></dc:creator>
		<pubDate>Mon, 22 Jun 2009 00:08:01 +0000</pubDate>
		<guid isPermaLink="false">http://conal.net/blog/?p=86#comment-443</guid>
		<description><![CDATA[&lt;p&gt;I always interpreted RT as the property that one may replace a symbol by its &lt;i&gt;definition&lt;/i&gt; without affecting semantics.  That applies to the pure fragment of Haskell, including pure functions manipulating the IO type and using its combinators.  However, there are quite a few IO &quot;primitives&quot;, such as getChar and newIORef.  RT does not apply to these primitives, because they have no definition.&lt;/p&gt;

&lt;p&gt;The pure lambda calculus -- just abstraction and application -- is completely RT.  Every symbol must have a definition (it is equivalent to a program where every &quot;symbol&quot; is bound by a lambda).  The very second you add something new -- numbers/addition, booleans/if-then-else -- it&#039;s likely you have introduced symbols with no definition.  They don&#039;t necessarily break RT, that term just doesn&#039;t mean anything for those symbols.&lt;/p&gt;

&lt;p&gt;Hmm.  &quot;... without affecting semantics&quot; was an interesting phrase in my definition.  Expressions have many types of semantics, all acting at once.  So when we talk about RT, we must do so &lt;i&gt;with respect to&lt;/i&gt; some given semantics.  Eg. we might be able to say that Haskell (sans IO, FFI, and seq) is RT wrt. its domain-theoretic semantics.  But certainly it is not wrt. its (say, GHC&#039;s) operational semantics, because definitions introduce sharing.&lt;/p&gt;
]]></description>
		<content:encoded><![CDATA[<p>I always interpreted RT as the property that one may replace a symbol by its <i>definition</i> without affecting semantics.  That applies to the pure fragment of Haskell, including pure functions manipulating the IO type and using its combinators.  However, there are quite a few IO &#8220;primitives&#8221;, such as getChar and newIORef.  RT does not apply to these primitives, because they have no definition.</p>

<p>The pure lambda calculus &#8212; just abstraction and application &#8212; is completely RT.  Every symbol must have a definition (it is equivalent to a program where every &#8220;symbol&#8221; is bound by a lambda).  The very second you add something new &#8212; numbers/addition, booleans/if-then-else &#8212; it&#8217;s likely you have introduced symbols with no definition.  They don&#8217;t necessarily break RT, that term just doesn&#8217;t mean anything for those symbols.</p>

<p>Hmm.  &#8220;&#8230; without affecting semantics&#8221; was an interesting phrase in my definition.  Expressions have many types of semantics, all acting at once.  So when we talk about RT, we must do so <i>with respect to</i> some given semantics.  Eg. we might be able to say that Haskell (sans IO, FFI, and seq) is RT wrt. its domain-theoretic semantics.  But certainly it is not wrt. its (say, GHC&#8217;s) operational semantics, because definitions introduce sharing.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: conal</title>
		<link>http://conal.net/blog/posts/notions-of-purity-in-haskell#comment-442</link>
		<dc:creator><![CDATA[conal]]></dc:creator>
		<pubDate>Sun, 21 Jun 2009 19:35:53 +0000</pubDate>
		<guid isPermaLink="false">http://conal.net/blog/?p=86#comment-442</guid>
		<description><![CDATA[&lt;p&gt;Paul Chiusano wrote:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I think it would be more useful if you would just give your argument as to why getStr is still RT according to your definition rather than trying to use the socratic method over this comment thread. :)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First, I&#039;m picking up something of a bait-and-switch going on here (unintentional, I presume).
I didn&#039;t say that getStr is RT (referentially transparent), nor that I was giving a definition of RT.&lt;/p&gt;

&lt;p&gt;It was you, not I, who claimed that getStr is RT.
I wouldn&#039;t make a claim either way, because I don&#039;t know what RT can mean for IO.&lt;/p&gt;

&lt;p&gt;Usually referential transparency is defined as meaning that a subexpression can be replaced by its value without change in meaning.
This definition is problematic in general, since expressions and values are different sorts of things.
Some types have a sort of normal form, which could be considered &quot;values&quot;.
For instance, for numeric types, we have numerals/literals.
For IO in particular, I don&#039;t know what plays the role of &quot;literals&quot;.&lt;/p&gt;

&lt;p&gt;Another definition of referential transparency is that any subexpression can be replaced by another expression that has the same value/semantics, without changing the meaning/value of the containing expression.
Again there&#039;s some subtlety.
When we say that two (sub)expressions do or do not &quot;have the same value&quot;, what do we mean by &quot;same&quot;?
For the statement to be meaningful, we have to define semantic equality.
I don&#039;t know of such a definition for IO.
Perhaps a compelling definition could exist, but perhaps not.&lt;/p&gt;

&lt;p&gt;IO carries the collective sins of our tribe, as the scapegoat did among the ancient Hebrews.
Or, as Simon Peyton Jones expressed it, &quot;The IO monad has become Haskell’s sin-bin.  Whenever we don’t understand something, we toss it in the IO monad.&quot;  (From &lt;a href=&quot;http://research.microsoft.com/en-us/um/people/simonpj/papers/haskell-retrospective/&quot; rel=&quot;nofollow&quot;&gt;Wearing the hair shirt - A retrospective on Haskell&lt;/a&gt;.)
Is it likely that we can then come along later and give a compelling and mathematically well-behaved notion of equality to our toxic waste pile?
Or will it insist on behaving anti-sociably, as our own home-grown &lt;a href=&quot;http://en.wikipedia.org/wiki/Toxic_Avenger&quot; rel=&quot;nofollow&quot;&gt;Toxic Avenger&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;Paul continues:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Let me give my argument as to why getStr (and other functions that have side effects) is RT. I think I have a more limited definition of RT: to me, a RT function is one with the property that any call to it can be replaced with its result without affecting the semantics of the program. I think of this as dictating that the function must have all its behavior reflected in its return value - there is not other way for it to propagate information to the rest of the program. It means that you can reason about program behavior by simple substitution - just replace each function call with the value that call refers to.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First, I&#039;d simplify/generalize away the role of functions here, and talk about &lt;em&gt;expressions&lt;/em&gt; (including function applications) rather than &lt;em&gt;functions&lt;/em&gt; as RT.
Something of a nit-pick I realize, but I don&#039;t know how else to get to clarity (and beyond opinions) on issues like this one.
As David R. MacIver said in &quot;&lt;a href=&quot;http://www.drmaciver.com/2009/05/a-problem-of-language/&quot; rel=&quot;nofollow&quot;&gt;A problem of language&lt;/a&gt;&quot;,&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Of course, once you start defining the term people will start arguing about the definitions. This is pretty tedious, I know. But as tedious as arguing about definitions is, it can’t hold a candle to arguing without definitions.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since &quot;getStr&quot; is not a function but is an expression, we&#039;ll probably want a definition that applies to expressions.&lt;/p&gt;

&lt;p&gt;Next, there are the troubling (to me at least) questions I raised above: 
What is the value of an IO sub-expression?
How could such a value be substituted into a program?
What does it mean to say whether or not the meaning of new expression is &lt;em&gt;equal&lt;/em&gt; to the meaning of the old expression?&lt;/p&gt;

&lt;p&gt;Continuing,&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Since Haskell forces you to thread a single IO value through all functions that perform IO, there is no way for the program to detect that values of type IO are actually do have side effects. I imagine functions that perform IO as returning a &quot;World&quot; object, which is then passed as an argument to the next function that performs IO, which returns a new World object, etc. We can pretend that the IO values that are chosen dynamically were in fact chosen ahead of time, before we even ran our program.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I&#039;ve read and re-read this paragraph, trying to sort it out, particularly how you&#039;d believe that &quot;Haskell forces you to thread a single IO value through all functions that perform IO&quot; or that &quot;values of type IO are actually do have side effects&quot;.&lt;/p&gt;

&lt;p&gt;My best guess is that you&#039;re confusing &quot;IO values&quot; with the hypothetical World values that GHC uses in its implementation of IO, and confusing &quot;functions that perform IO&quot; with IO values themselves.
I don&#039;t know whether the confusion is in your language or your thinking, or whether I&#039;m just somehow missing what you&#039;re saying here.&lt;/p&gt;

&lt;p&gt;By the way, GHC&#039;s World-passing representation of IO is just an implementation hack.
It&#039;s not a sound denotational model of Haskell IO, because it cannot account for concurrency.
It somehow became popular to think that the World type was something more than an implementation hack.&lt;/p&gt;

&lt;p&gt;There is a popular, and much simpler, argument about the referential transparency of IO in Haskell, which I think is very different from what you&#039;re saying.
In this perspective, the reason that &quot;there is no way for the program to detect that values of type IO are actually do have side effects&quot; is simply that they honestly &lt;em&gt;do not have side-effects&lt;/em&gt;.
No lie necessary.
IO values don&#039;t &lt;em&gt;do&lt;/em&gt; anything; they simply &lt;em&gt;are&lt;/em&gt;.
It is only a particular &lt;em&gt;interpretation&lt;/em&gt; of those values that gives rise to side-effects.
Sometimes people get confused about this distinction or think it&#039;s some kind of strange magic or con game.
I liken it to the situation with simple types like Boolean and Integer.
The values denoted by &quot;True&quot; and &quot;3+4&quot; have no side-effects, and yet the interpretation called &quot;print&quot; will indeed lead to a side-effect.&lt;/p&gt;

&lt;p&gt;Thus, many claim, IO in Haskell is a well-behaved, purely functional type, and Haskell&#039;s chaste status as purely functional is preserved.
I&#039;m not a big fan of this line of thought.
As I explained elsewhere, similar reasoning shows that &lt;a href=&quot;http://conal.net/blog/posts/the-c-language-is-purely-functional/&quot; rel=&quot;nofollow&quot;&gt;The C language is purely functional&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While this viewpoint &lt;em&gt;avoids disproving&lt;/em&gt; referential transparency IO in Haskell, it doesn&#039;t demonstrate referential transparency, because our definitions of referential transparency depend on &lt;em&gt;equality&lt;/em&gt;, and we don&#039;t have a definition of equality for IO.
Maybe we can come up with a sound and compelling definition that is consistent with concurrency and with everything tossed into the sin-bin so far and yet is somehow sound and compelling.&lt;/p&gt;
]]></description>
		<content:encoded><![CDATA[<p>Paul Chiusano wrote:</p>

<blockquote>
  <p>I think it would be more useful if you would just give your argument as to why getStr is still RT according to your definition rather than trying to use the socratic method over this comment thread. <img src="http://conal.net/blog/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /></p>
</blockquote>

<p>First, I&#8217;m picking up something of a bait-and-switch going on here (unintentional, I presume).
I didn&#8217;t say that getStr is RT (referentially transparent), nor that I was giving a definition of RT.</p>

<p>It was you, not I, who claimed that getStr is RT.
I wouldn&#8217;t make a claim either way, because I don&#8217;t know what RT can mean for IO.</p>

<p>Usually referential transparency is defined as meaning that a subexpression can be replaced by its value without change in meaning.
This definition is problematic in general, since expressions and values are different sorts of things.
Some types have a sort of normal form, which could be considered &#8220;values&#8221;.
For instance, for numeric types, we have numerals/literals.
For IO in particular, I don&#8217;t know what plays the role of &#8220;literals&#8221;.</p>

<p>Another definition of referential transparency is that any subexpression can be replaced by another expression that has the same value/semantics, without changing the meaning/value of the containing expression.
Again there&#8217;s some subtlety.
When we say that two (sub)expressions do or do not &#8220;have the same value&#8221;, what do we mean by &#8220;same&#8221;?
For the statement to be meaningful, we have to define semantic equality.
I don&#8217;t know of such a definition for IO.
Perhaps a compelling definition could exist, but perhaps not.</p>

<p>IO carries the collective sins of our tribe, as the scapegoat did among the ancient Hebrews.
Or, as Simon Peyton Jones expressed it, &#8220;The IO monad has become Haskell’s sin-bin.  Whenever we don’t understand something, we toss it in the IO monad.&#8221;  (From <a href="http://research.microsoft.com/en-us/um/people/simonpj/papers/haskell-retrospective/" rel="nofollow">Wearing the hair shirt &#8211; A retrospective on Haskell</a>.)
Is it likely that we can then come along later and give a compelling and mathematically well-behaved notion of equality to our toxic waste pile?
Or will it insist on behaving anti-sociably, as our own home-grown <a href="http://en.wikipedia.org/wiki/Toxic_Avenger" rel="nofollow">Toxic Avenger</a>?</p>

<p>Paul continues:</p>

<blockquote>
  <p>Let me give my argument as to why getStr (and other functions that have side effects) is RT. I think I have a more limited definition of RT: to me, a RT function is one with the property that any call to it can be replaced with its result without affecting the semantics of the program. I think of this as dictating that the function must have all its behavior reflected in its return value &#8211; there is not other way for it to propagate information to the rest of the program. It means that you can reason about program behavior by simple substitution &#8211; just replace each function call with the value that call refers to.</p>
</blockquote>

<p>First, I&#8217;d simplify/generalize away the role of functions here, and talk about <em>expressions</em> (including function applications) rather than <em>functions</em> as RT.
Something of a nit-pick I realize, but I don&#8217;t know how else to get to clarity (and beyond opinions) on issues like this one.
As David R. MacIver said in &#8220;<a href="http://www.drmaciver.com/2009/05/a-problem-of-language/" rel="nofollow">A problem of language</a>&#8220;,</p>

<blockquote>
  <p>Of course, once you start defining the term people will start arguing about the definitions. This is pretty tedious, I know. But as tedious as arguing about definitions is, it can’t hold a candle to arguing without definitions.</p>
</blockquote>

<p>Since &#8220;getStr&#8221; is not a function but is an expression, we&#8217;ll probably want a definition that applies to expressions.</p>

<p>Next, there are the troubling (to me at least) questions I raised above: 
What is the value of an IO sub-expression?
How could such a value be substituted into a program?
What does it mean to say whether or not the meaning of new expression is <em>equal</em> to the meaning of the old expression?</p>

<p>Continuing,</p>

<blockquote>
  <p>Since Haskell forces you to thread a single IO value through all functions that perform IO, there is no way for the program to detect that values of type IO are actually do have side effects. I imagine functions that perform IO as returning a &#8220;World&#8221; object, which is then passed as an argument to the next function that performs IO, which returns a new World object, etc. We can pretend that the IO values that are chosen dynamically were in fact chosen ahead of time, before we even ran our program.</p>
</blockquote>

<p>I&#8217;ve read and re-read this paragraph, trying to sort it out, particularly how you&#8217;d believe that &#8220;Haskell forces you to thread a single IO value through all functions that perform IO&#8221; or that &#8220;values of type IO are actually do have side effects&#8221;.</p>

<p>My best guess is that you&#8217;re confusing &#8220;IO values&#8221; with the hypothetical World values that GHC uses in its implementation of IO, and confusing &#8220;functions that perform IO&#8221; with IO values themselves.
I don&#8217;t know whether the confusion is in your language or your thinking, or whether I&#8217;m just somehow missing what you&#8217;re saying here.</p>

<p>By the way, GHC&#8217;s World-passing representation of IO is just an implementation hack.
It&#8217;s not a sound denotational model of Haskell IO, because it cannot account for concurrency.
It somehow became popular to think that the World type was something more than an implementation hack.</p>

<p>There is a popular, and much simpler, argument about the referential transparency of IO in Haskell, which I think is very different from what you&#8217;re saying.
In this perspective, the reason that &#8220;there is no way for the program to detect that values of type IO are actually do have side effects&#8221; is simply that they honestly <em>do not have side-effects</em>.
No lie necessary.
IO values don&#8217;t <em>do</em> anything; they simply <em>are</em>.
It is only a particular <em>interpretation</em> of those values that gives rise to side-effects.
Sometimes people get confused about this distinction or think it&#8217;s some kind of strange magic or con game.
I liken it to the situation with simple types like Boolean and Integer.
The values denoted by &#8220;True&#8221; and &#8220;3+4&#8243; have no side-effects, and yet the interpretation called &#8220;print&#8221; will indeed lead to a side-effect.</p>

<p>Thus, many claim, IO in Haskell is a well-behaved, purely functional type, and Haskell&#8217;s chaste status as purely functional is preserved.
I&#8217;m not a big fan of this line of thought.
As I explained elsewhere, similar reasoning shows that <a href="http://conal.net/blog/posts/the-c-language-is-purely-functional/" rel="nofollow">The C language is purely functional</a>.</p>

<p>While this viewpoint <em>avoids disproving</em> referential transparency IO in Haskell, it doesn&#8217;t demonstrate referential transparency, because our definitions of referential transparency depend on <em>equality</em>, and we don&#8217;t have a definition of equality for IO.
Maybe we can come up with a sound and compelling definition that is consistent with concurrency and with everything tossed into the sin-bin so far and yet is somehow sound and compelling.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Paul Chiusano</title>
		<link>http://conal.net/blog/posts/notions-of-purity-in-haskell#comment-441</link>
		<dc:creator><![CDATA[Paul Chiusano]]></dc:creator>
		<pubDate>Sun, 21 Jun 2009 17:36:04 +0000</pubDate>
		<guid isPermaLink="false">http://conal.net/blog/?p=86#comment-441</guid>
		<description><![CDATA[&lt;p&gt;Conal,&lt;/p&gt;

&lt;p&gt;I think it would be more useful if you would just give your argument as to why getStr is still RT according to your definition rather than trying to use the socratic method over this comment thread. :)&lt;/p&gt;

&lt;p&gt;Let me give my argument as to why getStr (and other functions that have side effects) is RT. I think I have a more limited definition of RT: to me, a RT function is one with the property that any call to it can be replaced with its result without affecting the semantics of the program. I think of this as dictating that the function must have all its behavior reflected in its return value - there is not other way for it to propagate information to the rest of the program. It means that you can reason about program behavior by simple substitution - just replace each function call with the value that call refers to.&lt;/p&gt;

&lt;p&gt;Since Haskell forces you to thread a single IO value through all functions that perform IO, there is no way for the program to detect that values of type IO are actually do have side effects. I imagine functions that perform IO as returning a &quot;World&quot; object, which is then passed as an argument to the next function that performs IO, which returns a new World object, etc. We can pretend that the IO values that are chosen dynamically were in fact chosen ahead of time, before we even ran our program.&lt;/p&gt;
]]></description>
		<content:encoded><![CDATA[<p>Conal,</p>

<p>I think it would be more useful if you would just give your argument as to why getStr is still RT according to your definition rather than trying to use the socratic method over this comment thread. <img src="http://conal.net/blog/wp-includes/images/smilies/icon_smile.gif" alt=":)" class="wp-smiley" /></p>

<p>Let me give my argument as to why getStr (and other functions that have side effects) is RT. I think I have a more limited definition of RT: to me, a RT function is one with the property that any call to it can be replaced with its result without affecting the semantics of the program. I think of this as dictating that the function must have all its behavior reflected in its return value &#8211; there is not other way for it to propagate information to the rest of the program. It means that you can reason about program behavior by simple substitution &#8211; just replace each function call with the value that call refers to.</p>

<p>Since Haskell forces you to thread a single IO value through all functions that perform IO, there is no way for the program to detect that values of type IO are actually do have side effects. I imagine functions that perform IO as returning a &#8220;World&#8221; object, which is then passed as an argument to the next function that performs IO, which returns a new World object, etc. We can pretend that the IO values that are chosen dynamically were in fact chosen ahead of time, before we even ran our program.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: conal</title>
		<link>http://conal.net/blog/posts/notions-of-purity-in-haskell#comment-440</link>
		<dc:creator><![CDATA[conal]]></dc:creator>
		<pubDate>Thu, 18 Jun 2009 21:26:43 +0000</pubDate>
		<guid isPermaLink="false">http://conal.net/blog/?p=86#comment-440</guid>
		<description><![CDATA[&lt;p&gt;Hi Paul,&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;You said of RT: &quot;the value of a closed expression (one not containing free variables) depends solely on the expression itself — not influenced by the dynamic conditions under which it is executed.&quot;&lt;/p&gt;
  
  &lt;p&gt;By this definition, even getStr :: IO String is not RT, since its value clearly depends on the dynamic conditions under which it is executed. Likewise if you change System.Info.os to return IO String.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Does the &lt;em&gt;value&lt;/em&gt; of &lt;code&gt;getStr&lt;/code&gt; depend on dynamic conditions?
How can you tell?
What do you mean when you say that one action (IO value) is the same as or is different from another action?&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;One thought I had is that it may be better to think of a Haskell program as not being fully closed - that is, there are certain free variables that are bound only when executing a Haskell program on a particular machine. For instance, the functions specifying the details of Int arithmetic could be considered free variables in a Haskell program. When we decide to run a Haskell program on some specific system, what we are really doing is supplying values for these free variables and running the resulting closed expression.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I get a queasy feeling about this suggestion.
I worry about arbitrariness sneaking in to our semantic model.
Why bind variables when assigning Haskell code to a particular &lt;em&gt;machine&lt;/em&gt;?
Why not bind whenever processing changes threads or cores?
Or hours?  The meaning of my code could change every hour, on the hour.
Or moment-to-moment, as in consistently non-RT languages.
Moreover, consider distributed execution, as mentioned previously in comments.&lt;br /&gt;
I really do believe that intelligently transient distributed execution will become the norm.
And functional languages could be ready &lt;em&gt;unless&lt;/em&gt; we make some semantically incautious choices and fail to fix the ones we&#039;ve already made.&lt;/p&gt;

&lt;p&gt;Besides, functional languages already have an elegant and semantically sound way to express values that depend on dynamic information: functions.
If we want code that depends on choice of OS, machine bit width, or time of day, I&#039;d be a lot more comfortable defining functions over arguments of those types.&lt;/p&gt;
]]></description>
		<content:encoded><![CDATA[<p>Hi Paul,</p>

<blockquote>
  <p>You said of RT: &#8220;the value of a closed expression (one not containing free variables) depends solely on the expression itself — not influenced by the dynamic conditions under which it is executed.&#8221;</p>
  
  <p>By this definition, even getStr :: IO String is not RT, since its value clearly depends on the dynamic conditions under which it is executed. Likewise if you change System.Info.os to return IO String.</p>
</blockquote>

<p>Does the <em>value</em> of <code>getStr</code> depend on dynamic conditions?
How can you tell?
What do you mean when you say that one action (IO value) is the same as or is different from another action?</p>

<blockquote>
  <p>One thought I had is that it may be better to think of a Haskell program as not being fully closed &#8211; that is, there are certain free variables that are bound only when executing a Haskell program on a particular machine. For instance, the functions specifying the details of Int arithmetic could be considered free variables in a Haskell program. When we decide to run a Haskell program on some specific system, what we are really doing is supplying values for these free variables and running the resulting closed expression.</p>
</blockquote>

<p>I get a queasy feeling about this suggestion.
I worry about arbitrariness sneaking in to our semantic model.
Why bind variables when assigning Haskell code to a particular <em>machine</em>?
Why not bind whenever processing changes threads or cores?
Or hours?  The meaning of my code could change every hour, on the hour.
Or moment-to-moment, as in consistently non-RT languages.
Moreover, consider distributed execution, as mentioned previously in comments.<br />
I really do believe that intelligently transient distributed execution will become the norm.
And functional languages could be ready <em>unless</em> we make some semantically incautious choices and fail to fix the ones we&#8217;ve already made.</p>

<p>Besides, functional languages already have an elegant and semantically sound way to express values that depend on dynamic information: functions.
If we want code that depends on choice of OS, machine bit width, or time of day, I&#8217;d be a lot more comfortable defining functions over arguments of those types.</p>
]]></content:encoded>
	</item>
</channel>
</rss>
