[Haskell-cafe] On the purity of Haskell

Conal Elliott conal at conal.net
Mon Jan 2 06:41:04 CET 2012

> ... World -> (x, World) ...

I look at this World parameter as purely hypothetical, a trick used to gain
> an intuition. Whereas Jerzy (I think) uses it to claim Haskell is
> referentially transparent - those differing x and y values come from
> different worlds, or different world-states.

I don't see this interpretation in Jerzy's words, and I'd be very surprised
if he had that sort of argument in mind.

If main returns a function of type "World -> (x, World)" wrapped in ...

Main does not return or denote such a thing. The idea that Haskell IO can
be accurately explained as (i.e., denotes) World -> (x,World) is a
persistent myth. That model cannot explain concurrency (even with the
outside world) or nondeterminism, both of which are part of Haskell IO. We
don't have an precise & accurate denotational model for IO, in contrast to
most other types in Haskell. Which is to say that while much of Haskell
programming is denotative, IO programming is not. Peter Landin, an
important figure in functional programming, proposed and defined this term
"denotative" as a substantive & precise replacement for the fuzzier notions
of "functional" and "declarative". He offered his definition and suggested
that "When faced with a new notation that borrows the functional appearance
of everyday algebra, it is (c) that gives us a test for whether the
notation is genuinely functional or merely masquerading."

Of course, various subsets of IO can be precisely and accurately modeled,
but so far not IO as we use it. It's very unlikely that we ever will have
such a (precise & accurate) model, and by design, as explained at
http://conal.net/blog/posts/notions-of-purity-in-haskell/#comment-22829 .

  - Conal

On Sun, Jan 1, 2012 at 7:43 PM, Steve Horne <sh006d3592 at blueyonder.co.uk>wrote:

> On 01/01/2012 22:57, Jerzy Karczmarczuk wrote:
>> Dan Doel :
>> ...
>>> Also, the embedded IO language does not have this property.
>>>     do x<- m ; f x x
>>> is different from
>>>     do x<- m ; y<- m ; f x y
>>> and so on. This is why you shouldn't write your whole program with IO
>>> functions; it lacks nice properties for working with your code.
>> Sorry, what are you trying to suggest?
>> You show two OBVIOUSLY different pieces of code, and you say that they
>> are different.
>> If, by chance, some newbie reads that and gets the impression that
>> (<-) is something equivalent to (=), you are serving the devil.
>>  Speaking as the devil...
> The do-notation sugar may confuse the issue - the <- looks like an
> operator, but translating to binds-and-lambdas form suggests otherwise.
> Quick translations (I hope no mistakes) with lots of parens...
>  m >>= (\x -> (f x x))
>  m >>= (\x -> (m >>= (\y -> (f x y))))
> At first sight, these two expressions can give different results for
> reasons other than evaluation order. In particular, there are two bind
> operators, not just one.
> That is, x and y could get different values for reasons other than the two
> m references referring to different things. So... is that true?
> Of course even the bind operator arguably isn't primitive. We could
> translate to get rid of those too, and see what lies underneath. This is
> where we start seeing functions of type...
>  World -> (x, World)
> Problem - this level of abstraction is hypothetical. It is not part of the
> Haskell language. Haskell specifically defines the IO monad to be a black
> box.
> I look at this World parameter as purely hypothetical, a trick used to
> gain an intuition. Whereas Jerzy (I think) uses it to claim Haskell is
> referentially transparent - those differing x and y values come from
> different worlds, or different world-states. I'm not entirely sure, though,
> as we got sidetracked.
> If main returns a function of type "World -> (x, World)" wrapped in a
> monad context, then there is referential transparency as defined in
> computer science. But is that a fair claim?
> In this model, Haskell is an interpreted language for compositing
> functions. We can call those functions programs. The executable is a
> translation of the function returned by main, but *not* a translation of
> the source code.
> But GHC is called a compiler, and compilation is usually considered a kind
> of translation - the executable is a translation of the source code. GHCi
> is an interpreter, but it doesn't stop at returning a function of type
> World -> (x, World) - it does the I/O. And the reason we use these terms is
> because, as programmers, we think of the executable as the program - as a
> translation of the source code.
> So what main returns - that hypothetical function World -> (x, World) -
> isn't just a product of the program, it's also a representation of the
> program.
> I've made similar points before, but how do they work out this time...
> So...
>  when           evaluate what             effects  referentially
> transparent
>  -------------  ------------------------  ------- -------------------------
>  compile-time   main                      no       yes
>  run-time       main someParticularWorld  yes      yes(?)
> I've proved effects at run-time, but in this model, the intermediate and
> final world-states are products of the evaluation of that "main
> someParticularWorld" expression. Even the results extracted from input
> actions are referentially transparent - or if not, we're dealing with the
> philosophy of determinism.
> It's probable that Jerzy told me this earlier and I wasn't ready to hear
> it then.
> However - we can say basically the same things about C. The World
> parameter is implicit in C but then it's implicit in Haskell too.
> Everything inside the IO monad black box is outside the scope of the
> Haskell language except in that semantics are defined for the primitive IO
> actions - basically what happens when a result is extracted out as part of
> evaluating a bind. That "(?)" in the "yes(?)" is because this is all
> contingent on that hypothetical World -> (x, World) function hidden inside
> the IO monad context, which is not specified in the Haskell language.
> When I say that Haskell lacks referential transparency because the
> execution of primitive IO actions is tied to the evaluation of the bind
> operators that extract out their results, and different executions of the
> same action yield different results, I'm only appealing to the defined
> semantics of the Haskell language. I'm not appealing to a hypothetical
> model where the world is passed as a parameter.
> OTOH, this World -> (x, World) model is much more appealing than my
> partially-evaluated-functions-**as-AST-nodes model.
> So - the issue seems to be whether the IO monad is a context holding
> world-manipulating functions, or whether it's a black box with semantics
> specified at the bind level. And if referential transparency is decided at
> this level, what practical relevance does it have?
> It's probably better to stick with "the functional core is referentially
> transparent - IO actions break that, so don't overuse the IO monad". You
> can argue "may or may not break that depending on your viewpoint", but if
> you can't objectively decide which viewpoint is correct, then you haven't
> proven referential transparency.
> ______________________________**_________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/**mailman/listinfo/haskell-cafe<http://www.haskell.org/mailman/listinfo/haskell-cafe>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20120101/34107066/attachment.htm>

More information about the Haskell-Cafe mailing list