

She: The Strathclyde Haskell Enhancement - brudgers
https://personal.cis.strath.ac.uk/conor.mcbride/pub/she/

======
krylon
My own experiences with Haskell have been... unfortunate (either I am too
stupid or my brain has been damaged by imperative programming languages). But
this is easily the funniest introduction to any piece of software I have ever
come across.

~~~
tjradcliffe
Someone on HN suggested this guide to Haskell a few days ago:
[http://en.wikibooks.org/wiki/Haskell](http://en.wikibooks.org/wiki/Haskell)

I'm finding it the first useful introduction to the language I've encountered.
Like you, my experiences have been less than exemplary, and I'm way too
arrogant to accept that I'm either stupid or brain damaged. Every year or so I
take a run at Haskell, and this time I think I'm going to get it. I know a
dozen-odd languages, including a fairly expert grasp of APL and Mathematica,
both of which are a bit odd in their approach to life. Haskell is genuinely
weirder than most, and the entire Haskell community's apparent total ignorance
of the of the most rudimentary principles of pedagogy make the learning curve
unreasonably steep.

The fact that most Haskell tutorials start out with contradictions is an
example of this. Pedagogy 101: don't make false claims about the subject _in
terms of the concepts you can reasonably expect the student to have_.

For example, electrical engineers should never introduce the concept of
"negative resistance" by starting off talking about "negative resistance".
They should first introduce the concept of _generalized resistance_ (dV/dI
rather than V/I) and then show how _generalized resistance_ can be negative.
To tell a student that there is such a thing as "negative resistance" when you
know full well that "resistance" in the student's mind is not generalized but
defined by a relation such that it cannot possibly be negative is simply
incompetence on the part of the teacher.

By the same token, it doesn't matter one whit that "the language" is side-
effect free when "the runtime" implements side effects when the student can
reasonably expected to understand "language" to mean "language plus runtime"
as it is in every other case. Actually: it does matter, and it should be
explained in those terms. Otherwise students will rightly reject the language
as some kind of snake-oil gibberish promoted by arrogant hucksters.

No Haskell tutorial should ever make the false claim that "the language" (as
understood by any reasonable student) is "purely functional". Students aren't
stupid and haven't been brain-damaged by imperative languages. They know that
"the language" covers the whole package in ordinary parlance, including the
runtime. When we talk about Perl or Python or C++ or FORTRAN that's what we
mean. There is absolutely no basis for anyone to ever assume any other
understanding on the part of the student.

So tell people "Haskell is implemented in such a way that it can be treated as
a purely functional language for the purpose of static analysis even though at
runtime there are various clever tricks that still allow it to implement side-
effects like IO". That is a truthful statement. "Haskell is a pure functional
language and for every function call the return value depends only on its
arguments" is false, outside of a tortured and bizarre interpretation of the
terminology that has no apparent purpose but to misrepresent reality to
outsiders.

There are some pretty cool things about Haskell. The type inference system is
powerful, useful and interesting. It's remarkable to see how far a nominally
(but not actually) purely functional language can be pushed, and the way
various hacks are used to overcome the limitations of purely functional
languages is incredibly clever. The creators of Haskell should be celebrating
those feats, not hiding behind false claims that the language+runtime is
"truly" purely functional when it manifestly is not.

Edit: Concrete example: to be a purely functional language function values
must depend only on their arguments. Here is an example of a Haskell function
whose value does not depend only on its arguments:

    
    
        notPurelyFunctional :: Double -> IO Double  
        notPurelyFunctional x = do  
            z <- putStrLn "Please enter a number: "  
            name <- getLine  
            let y = read name ::Double  
            return (x+y)  
    

If we do something like:

    
    
        value1 <- notPurelyFunctional 5.0  
        value2 <- notPurelyFunctional 5.0  
        value1 == value2  
    

we have no idea what "value1 == value2" will evaluate to, so either:

a) The above code is _not part of the Haskell language_ (which would be weird
as it all runs just fine under GHC, and "stuff that runs under GHC" is what
any ordinary person means by "Haskell")

or

b) Haskell is not a "pure functional language" the way that term is ordinarily
understood, which is: "calling the same function multiple times with the same
arguments will always produce the same results" (in which case "value1 ==
value2" must evaluate to "True", which it does not in general when running the
above code).

~~~
cousin_it
Q: Is it true that the return value of any Haskell function depends only on
its arguments?

A: Yes, barring tricks like unsafePerformIO. But you can write perfectly good
programs that do IO without these tricks anyway.

Q: Okay, genius. What about functions like getLine, which reads a line from
the console?

A: getLine isn't a function.

Q: What?

A: All functions in Haskell have types like "a -> b" for some a and b. But
you'll notice that the type of getLine doesn't have an arrow in it, it's just
"IO String".

Q What do you mean, it's not a function? I can call it right here, by doing
"do name <\- getLine"!

A: That's not the syntax for calling functions in Haskell, that's monadic do
notation. The syntax for calling functions is "foo x y".

Q: This is outrageous. So you're saying that getLine is just an inert value?

A: Yes.

Q: But what is that value? What's inside the type "IO String"? I'd always
assumed that it was a kind of wrapper around a String, with some type system
nastiness so people don't misuse it.

A: No, I'm afraid it can't be anything as simple as that. And it certainly
can't contain a String, because then getLine couldn't be the same value all
the time.

Q: Wait, you're saying that it doesn't even contain a String? Then what is it,
really?

A: The implementation of IO types is kind of private to the runtime. But you
can imagine that for any Haskell type X, "IO X" is a syntax tree of a side-
effecting C program that produces an X.

Q: I see. So getLine really is the same value all the time. But how do you
"run" the syntax tree that's hidden inside getLine, to actually get a String?

A: You generally don't. Instead you combine them together into one large tree
and call it "main", and the runtime takes it from there.

Q: That seems like a lot of work. At the very least, why doesn't the language
add some special syntax for combining syntax trees, so people don't have to
deal with plumbing?

A: Yeah, that's what monadic do notation was invented for. Unfortunately, it
was a bit too successful and some people started confusing it with actual
imperative code :-)

~~~
tjradcliffe
"and then the runtime takes it from there" is of course the right answer, but
_no one_ upon first encountering Haskell understands the distinction between
"the language" and "the runtime", so all the insistence that "the language" is
"purely functional" is utterly misleading.

Furthermore, the claim that "getLine is really the same value all the time" is
false. If that were the case, then any operation on getLine would return the
same value, which it does not.

Edit: And in any case, the question is not whether "getLine" is a function,
but whether "notpurelyFunctional" is. It has the signature of a function, but
its return value certainly doesn't depend only on its arguments, or we would
be able to say if value1 == value2 was true or not, and we can't.

Basically, any claim with the word "really" in it evaluates to false (in
philosophy claims about what is "really" or "really really" true are sometimes
enhanced by what is known as "a certain percussive emphasis.")

I think monads are an incredibly clever way of working side-effects into a
language while maintaining an interesting level of functional purity. But the
way the concepts are presented are just not conducive to conveying them to
newbs, who will rightly call bullshit based on what words like "the language"
are normally construed to mean.

~~~
cousin_it
> _but its return value certainly doesn 't depend only on its arguments_

Note that value1 and value2 are not, and cannot possibly be, return values of
notPurelyFunctional. The type of notPurelyFunctional says its return value has
type IO Double, but value1 and value2 have type Double. IO Double is not
Double, doesn't contain a Double, and cannot be converted to Double by a
function call.

It sounds like you still think that the syntax "do x <\- foo" means something
like "let x be the result of some function call involving foo". Actually it
can't be anything like that, it translates to something more compicated.

> _If that were the case, then any operation on getLine would return the same
> value_

Yes, and moreover, any operation on notPurelyFunctional 5.0 always returns the
same value.

You have my honest word that I have some experience with Haskell and believe
these things to be 100% true, with no wishy-washy philosophical caveats. I
know exactly how to write an interpreter in which the machine representation
of something like "notPurelyFunctional 5.0" will be immutable bit-for-bit,
without using any dirty tricks like pointers to mutable memory. And I know
that it's immutable in actual Haskell implementations as well.

------
Argorak
Hehe, "she". Great. I think the project would be better off with less bad
jokes in the README.

~~~
tel
The unfortunate part with regard to your wish is that Dr. McBride is a
professional punmaker who was poached by Strathclyde for his side hobby in
theoretical computer science.

~~~
saidajigumi
AFAICT, this (the punmaking, and language games in general) is actually a
prime attribute of PL researchers, at least in several major PL
subdisciplines. It's been awhile since I've cracked open the POPL proceedings
or the like, but ... wow, just wow.

One of my favorites was a (peer-reviewed, published!) paper with this gem of a
footnote in the first column: _This work supported in part by cinder blocks._

~~~
long
I've noticed this as well. Why is PL so punny?

Related question: are there other interesting quirks of various CS subfields?

~~~
harryjo
Because they are _language_ professionals, who enjoy studying languages and
packing as much power as they can into a language -- computer or human.

~~~
long
In my experience, linguists are _not_ terribly punny, though -- what accounts
for this difference?

(FWIW, my first-hand experience has mainly been with psycholinguists and
functional programming folks)

~~~
taejo
Linguists are language _analysts_ whereas programming language people are
language _creators_ ; perhaps this explains why the later _create_ more
wordplay?

