Re: New type of ($) operator in GHC 8.0 is problematic

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
144 messages Options
1234 ... 8
Reply | Threaded
Open this post in threaded view
|

Re: New type of ($) operator in GHC 8.0 is problematic

Johannes Waldmann-2
As Manuel wrote:

> I expect that every single person teaching Haskell
> is going to be unhappy about it.

Indeed I am. (Will be teaching beginners next term.)

- J.W.
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: New type of ($) operator in GHC 8.0 is problematic

Colin Adams
What's changed?

On 5 February 2016 at 16:14, Johannes Waldmann <[hidden email]> wrote:
As Manuel wrote:

> I expect that every single person teaching Haskell
> is going to be unhappy about it.

Indeed I am. (Will be teaching beginners next term.)

- J.W.
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: New type of ($) operator in GHC 8.0 is problematic

Johannes Waldmann-2

> What's changed?

I was referring to a discussion on ghc-devs, see
https://mail.haskell.org/pipermail/ghc-devs/2016-February/011268.html
and mixed up addresses when replying.

- J.

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: New type of ($) operator in GHC 8.0 is problematic

Tom Ellis
On Fri, Feb 05, 2016 at 05:25:15PM +0100, Johannes Waldmann wrote:
> > What's changed?
>
> I was referring to a discussion on ghc-devs, see
> https://mail.haskell.org/pipermail/ghc-devs/2016-February/011268.html
> and mixed up addresses when replying.

I'm glad you did, because this is the first I've heard of it!
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: New type of ($) operator in GHC 8.0 is problematic

Kyle Hanson-2
I am also happy the discussion was posted here. Although I don't teach Haskell professionally, one of the things I loved to do was show people how simple Haskell really was by inspecting types and slowly putting the puzzle pieces together. 

Summary of the problem for others:
From Takenobu Tani
Before ghc7.8:

  Prelude> :t foldr
  foldr :: (a -> b -> b) -> b -> [a] -> b

  Prelude> :t ($)
  ($) :: (a -> b) -> a -> b

  Beginners should only understand about following:

    * type variable (polymorphism)


After ghc8.0:

  Prelude> :t foldr
  foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b

  Prelude> :t ($)
  ($)
    :: forall (w :: GHC.Types.Levity) a (b :: TYPE w).
       (a -> b) -> a -> b


With this change it looks like I will no longer be able to keep `$` in my toolbox since telling a beginner its "magic" goes against what I believe Haskell is good at, being well defined and easy to understand (Not well defined in terms of Types but well defined in terms of ability to precisely and concisely explain and define whats going on).

It looks like where the discussion is going is to have these types show by default but eventually have an Alternative prelude for beginners.

From Richard Eisenberg:
- It's interesting that the solution to the two problems Takenobu pulls out below (but others have hinted at in this thread) is by having an alternate Prelude for beginners. I believe that having an alternate beginners' Prelude is becoming essential. I know I'm not the first one to suggest this, but a great many issues that teachers of Haskell have raised with me and posts on this and other lists would be solved by an alternate Prelude for beginners.
I don't like the idea of fragmenting Haskell into "beginners" and "advanced" versions. Its hard enough to get people to believe Haskell is easy. If they see that they aren't using the "real" prelude, Haskell will still be this magic black box that is too abstract and difficult to understand. If they have to use a "dumbed down" version of Haskell to learn, its not as compelling.

There is something powerful about using the same idiomatic tools as the "big boys" and have the tools still be able to be easy to understand.... by default. Adding complexity to the default Haskell runs the risk of further alienating newcomers to the language who have a misconception that its too hard.

Admittedly, I am not well informed of the state of GHC 8.0 development and haven't had time to fully look into the situation. I am very interested to see where this conversation and the default complexity of Haskell goes.

--
Kyle


On Fri, Feb 5, 2016 at 8:26 AM, Tom Ellis <[hidden email]> wrote:
On Fri, Feb 05, 2016 at 05:25:15PM +0100, Johannes Waldmann wrote:
> > What's changed?
>
> I was referring to a discussion on ghc-devs, see
> https://mail.haskell.org/pipermail/ghc-devs/2016-February/011268.html
> and mixed up addresses when replying.

I'm glad you did, because this is the first I've heard of it!
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: New type of ($) operator in GHC 8.0 is problematic

Christopher Allen
I don't want, nor do I think it's a good idea, to have a beginners' Prelude. My point about ($) was not expressly about beginners, it was about intermediate practitioners too.


On Fri, Feb 5, 2016 at 11:55 AM, Kyle Hanson <[hidden email]> wrote:
I am also happy the discussion was posted here. Although I don't teach Haskell professionally, one of the things I loved to do was show people how simple Haskell really was by inspecting types and slowly putting the puzzle pieces together. 

Summary of the problem for others:
From Takenobu Tani
Before ghc7.8:

  Prelude> :t foldr
  foldr :: (a -> b -> b) -> b -> [a] -> b

  Prelude> :t ($)
  ($) :: (a -> b) -> a -> b

  Beginners should only understand about following:

    * type variable (polymorphism)


After ghc8.0:

  Prelude> :t foldr
  foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b

  Prelude> :t ($)
  ($)
    :: forall (w :: GHC.Types.Levity) a (b :: TYPE w).
       (a -> b) -> a -> b


With this change it looks like I will no longer be able to keep `$` in my toolbox since telling a beginner its "magic" goes against what I believe Haskell is good at, being well defined and easy to understand (Not well defined in terms of Types but well defined in terms of ability to precisely and concisely explain and define whats going on).

It looks like where the discussion is going is to have these types show by default but eventually have an Alternative prelude for beginners.

From Richard Eisenberg:
- It's interesting that the solution to the two problems Takenobu pulls out below (but others have hinted at in this thread) is by having an alternate Prelude for beginners. I believe that having an alternate beginners' Prelude is becoming essential. I know I'm not the first one to suggest this, but a great many issues that teachers of Haskell have raised with me and posts on this and other lists would be solved by an alternate Prelude for beginners.
I don't like the idea of fragmenting Haskell into "beginners" and "advanced" versions. Its hard enough to get people to believe Haskell is easy. If they see that they aren't using the "real" prelude, Haskell will still be this magic black box that is too abstract and difficult to understand. If they have to use a "dumbed down" version of Haskell to learn, its not as compelling.

There is something powerful about using the same idiomatic tools as the "big boys" and have the tools still be able to be easy to understand.... by default. Adding complexity to the default Haskell runs the risk of further alienating newcomers to the language who have a misconception that its too hard.

Admittedly, I am not well informed of the state of GHC 8.0 development and haven't had time to fully look into the situation. I am very interested to see where this conversation and the default complexity of Haskell goes.

--
Kyle


On Fri, Feb 5, 2016 at 8:26 AM, Tom Ellis <[hidden email]> wrote:
On Fri, Feb 05, 2016 at 05:25:15PM +0100, Johannes Waldmann wrote:
> > What's changed?
>
> I was referring to a discussion on ghc-devs, see
> https://mail.haskell.org/pipermail/ghc-devs/2016-February/011268.html
> and mixed up addresses when replying.

I'm glad you did, because this is the first I've heard of it!
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe




--
Chris Allen
Currently working on http://haskellbook.com

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: New type of ($) operator in GHC 8.0 is problematic

Richard Eisenberg-2
In reply to this post by Kyle Hanson-2
Perhaps it will aid the discussion to see that the type of ($) will, for better or worse, be changing again before 8.0.

The problem is described in GHC ticket #11471. The details of "why" aren't all that important for this discussion, but the resolution might be. The new (hopefully final!) type of ($) will be:

> ($) :: forall (r :: RuntimeRep) (a :: *) (b :: TYPE r). (a -> b) -> a -> b

Once again, it's easy enough to tweak the pretty-printer to hide the complexity. But perhaps it's not necessary. The difference as far as this conversation is concerned is that Levity has been renamed to RuntimeRep. I think this is an improvement, because now it's not terribly hard to explain:

---
1. Types of kind * have values represented by pointers. This is the vast majority of data in Haskell, because almost everything in Haskell is boxed.
2. But sometimes, we don't care how a value is represented. In this case, we can be polymorphic in the choice of representation, just like `length` is polymorphic in the choice of list element type.
3. ($) works with functions whose result can have any representation, as succinctly stated in the type. Note that the argument to the function must be boxed, however, because the implementation of ($) must store and pass the argument. It doesn't care at all about the result, though, allowing for representation-polymorphism.

In aid of this explanation, we can relate this all to Java. The reference types in Java (e.g., Object, int[], Boolean) are all like types of kind *. The primitive types in Java (int, boolean, char) do not have kind *. Java allows type abstraction (that is, generics) only over the types of kind *. Haskell is more general, allowing abstraction over primitive types via representation polymorphism.
---

Could this all be explained to a novice programmer? That would be a struggle. But it could indeed be explained to an intermediate programmer in another language just learning Haskell.

For point of comparison, Java is widely used as a teaching language. And yet one of the simplest programs is

public class HelloWorld
{
  public static void main(String[] args)
  {
    System.out.println("Hello, world!");
  }
}

When I taught Java (I taught high-school full time for 8 years), I would start with something similar to this and have to tell everyone to ignore 90% of what was written. My course never even got to arrays and `static`! That was painful, but everyone survived. This is just to point out that Haskell isn't the only language with this problem. Not to say we shouldn't try to improve!

We're in a bit of a bind in all this. We really need the fancy type for ($) so that it can be used in all situations where it is used currently. The old type for ($) was just a plain old lie. Now, at least, we're not lying. So, do we 1) lie, 2) allow the language to grow, or 3) avoid certain growth because it affects how easy the language is to learn? I don't really think anyone is advocating for (3) exactly, but it's hard to have (2) and not make things more complicated -- unless we have a beginners' mode or other features in, say, GHCi that aid learning. As I've said, I'm in full favor of adding these features.

Richard

On Feb 5, 2016, at 12:55 PM, Kyle Hanson <[hidden email]> wrote:

I am also happy the discussion was posted here. Although I don't teach Haskell professionally, one of the things I loved to do was show people how simple Haskell really was by inspecting types and slowly putting the puzzle pieces together. 

Summary of the problem for others:
From Takenobu Tani
Before ghc7.8:

  Prelude> :t foldr
  foldr :: (a -> b -> b) -> b -> [a] -> b

  Prelude> :t ($)
  ($) :: (a -> b) -> a -> b

  Beginners should only understand about following:

    * type variable (polymorphism)


After ghc8.0:

  Prelude> :t foldr
  foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b

  Prelude> :t ($)
  ($)
    :: forall (w :: GHC.Types.Levity) a (b :: TYPE w).
       (a -> b) -> a -> b


With this change it looks like I will no longer be able to keep `$` in my toolbox since telling a beginner its "magic" goes against what I believe Haskell is good at, being well defined and easy to understand (Not well defined in terms of Types but well defined in terms of ability to precisely and concisely explain and define whats going on).

It looks like where the discussion is going is to have these types show by default but eventually have an Alternative prelude for beginners.

From Richard Eisenberg:
- It's interesting that the solution to the two problems Takenobu pulls out below (but others have hinted at in this thread) is by having an alternate Prelude for beginners. I believe that having an alternate beginners' Prelude is becoming essential. I know I'm not the first one to suggest this, but a great many issues that teachers of Haskell have raised with me and posts on this and other lists would be solved by an alternate Prelude for beginners.
I don't like the idea of fragmenting Haskell into "beginners" and "advanced" versions. Its hard enough to get people to believe Haskell is easy. If they see that they aren't using the "real" prelude, Haskell will still be this magic black box that is too abstract and difficult to understand. If they have to use a "dumbed down" version of Haskell to learn, its not as compelling.

There is something powerful about using the same idiomatic tools as the "big boys" and have the tools still be able to be easy to understand.... by default. Adding complexity to the default Haskell runs the risk of further alienating newcomers to the language who have a misconception that its too hard.

Admittedly, I am not well informed of the state of GHC 8.0 development and haven't had time to fully look into the situation. I am very interested to see where this conversation and the default complexity of Haskell goes.

--
Kyle


On Fri, Feb 5, 2016 at 8:26 AM, Tom Ellis <[hidden email]> wrote:
On Fri, Feb 05, 2016 at 05:25:15PM +0100, Johannes Waldmann wrote:
> > What's changed?
>
> I was referring to a discussion on ghc-devs, see
> https://mail.haskell.org/pipermail/ghc-devs/2016-February/011268.html
> and mixed up addresses when replying.

I'm glad you did, because this is the first I've heard of it!
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: New type of ($) operator in GHC 8.0 is problematic

Christopher Allen
Changing the name doesn't fix the issue. The issue is the noise and the referent, not the referrer. There's a habit of over-focusing on names in programming communities. I think it'd be a mistake to do that here and risk missing the point.

You can make all of the keywords in the Java example salient early on, but you cannot make the implementation details you're exposing in the type of ($) relevant unless they already have a year or two of Haskell under their belts. Listing out the keywords:

1. public

2. class

3. (class name)

4. static

5. void

6. (method name)

7. (method arguments)

Explaining public, class, static, and void usually happens pretty soon after the basics in a Java course. Importantly, they're things you _need_ to know to get things done properly in Java. The same is not true of what is mentioned in the type of ($).

The implicit prenex form and forall are irrelevant for learners until they get to Rank2/RankN which is very much beyond, "I am learning Haskell" and into, "I am designing an API in Haskell for other people to use". * vs. # is something many working and hobbyist Haskellers I've known will scarcely know anything about.

There is a big difference, to my mind, between what is being exposed here in Java versus what is being exposed in the type ($). Consider that the boxed/unboxed distinction exists in Java but needn't come up in any beginner tutorials.

>Types of kind * have values represented by pointers. This is the vast majority of data in Haskell, because almost everything in Haskell is boxed.

We can't assume Haskell learners know what pointers are. This, again, creates unnecessary noise for learners by forcing exposure to things that are irrelevant for a very long time.


On Fri, Feb 5, 2016 at 12:13 PM, Richard Eisenberg <[hidden email]> wrote:
Perhaps it will aid the discussion to see that the type of ($) will, for better or worse, be changing again before 8.0.

The problem is described in GHC ticket #11471. The details of "why" aren't all that important for this discussion, but the resolution might be. The new (hopefully final!) type of ($) will be:

> ($) :: forall (r :: RuntimeRep) (a :: *) (b :: TYPE r). (a -> b) -> a -> b

Once again, it's easy enough to tweak the pretty-printer to hide the complexity. But perhaps it's not necessary. The difference as far as this conversation is concerned is that Levity has been renamed to RuntimeRep. I think this is an improvement, because now it's not terribly hard to explain:

---
1. Types of kind * have values represented by pointers. This is the vast majority of data in Haskell, because almost everything in Haskell is boxed.
2. But sometimes, we don't care how a value is represented. In this case, we can be polymorphic in the choice of representation, just like `length` is polymorphic in the choice of list element type.
3. ($) works with functions whose result can have any representation, as succinctly stated in the type. Note that the argument to the function must be boxed, however, because the implementation of ($) must store and pass the argument. It doesn't care at all about the result, though, allowing for representation-polymorphism.

In aid of this explanation, we can relate this all to Java. The reference types in Java (e.g., Object, int[], Boolean) are all like types of kind *. The primitive types in Java (int, boolean, char) do not have kind *. Java allows type abstraction (that is, generics) only over the types of kind *. Haskell is more general, allowing abstraction over primitive types via representation polymorphism.
---

Could this all be explained to a novice programmer? That would be a struggle. But it could indeed be explained to an intermediate programmer in another language just learning Haskell.

For point of comparison, Java is widely used as a teaching language. And yet one of the simplest programs is

public class HelloWorld
{
  public static void main(String[] args)
  {
    System.out.println("Hello, world!");
  }
}

When I taught Java (I taught high-school full time for 8 years), I would start with something similar to this and have to tell everyone to ignore 90% of what was written. My course never even got to arrays and `static`! That was painful, but everyone survived. This is just to point out that Haskell isn't the only language with this problem. Not to say we shouldn't try to improve!

We're in a bit of a bind in all this. We really need the fancy type for ($) so that it can be used in all situations where it is used currently. The old type for ($) was just a plain old lie. Now, at least, we're not lying. So, do we 1) lie, 2) allow the language to grow, or 3) avoid certain growth because it affects how easy the language is to learn? I don't really think anyone is advocating for (3) exactly, but it's hard to have (2) and not make things more complicated -- unless we have a beginners' mode or other features in, say, GHCi that aid learning. As I've said, I'm in full favor of adding these features.

Richard

On Feb 5, 2016, at 12:55 PM, Kyle Hanson <[hidden email]> wrote:

I am also happy the discussion was posted here. Although I don't teach Haskell professionally, one of the things I loved to do was show people how simple Haskell really was by inspecting types and slowly putting the puzzle pieces together. 

Summary of the problem for others:
From Takenobu Tani
Before ghc7.8:

  Prelude> :t foldr
  foldr :: (a -> b -> b) -> b -> [a] -> b

  Prelude> :t ($)
  ($) :: (a -> b) -> a -> b

  Beginners should only understand about following:

    * type variable (polymorphism)


After ghc8.0:

  Prelude> :t foldr
  foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b

  Prelude> :t ($)
  ($)
    :: forall (w :: GHC.Types.Levity) a (b :: TYPE w).
       (a -> b) -> a -> b


With this change it looks like I will no longer be able to keep `$` in my toolbox since telling a beginner its "magic" goes against what I believe Haskell is good at, being well defined and easy to understand (Not well defined in terms of Types but well defined in terms of ability to precisely and concisely explain and define whats going on).

It looks like where the discussion is going is to have these types show by default but eventually have an Alternative prelude for beginners.

From Richard Eisenberg:
- It's interesting that the solution to the two problems Takenobu pulls out below (but others have hinted at in this thread) is by having an alternate Prelude for beginners. I believe that having an alternate beginners' Prelude is becoming essential. I know I'm not the first one to suggest this, but a great many issues that teachers of Haskell have raised with me and posts on this and other lists would be solved by an alternate Prelude for beginners.
I don't like the idea of fragmenting Haskell into "beginners" and "advanced" versions. Its hard enough to get people to believe Haskell is easy. If they see that they aren't using the "real" prelude, Haskell will still be this magic black box that is too abstract and difficult to understand. If they have to use a "dumbed down" version of Haskell to learn, its not as compelling.

There is something powerful about using the same idiomatic tools as the "big boys" and have the tools still be able to be easy to understand.... by default. Adding complexity to the default Haskell runs the risk of further alienating newcomers to the language who have a misconception that its too hard.

Admittedly, I am not well informed of the state of GHC 8.0 development and haven't had time to fully look into the situation. I am very interested to see where this conversation and the default complexity of Haskell goes.

--
Kyle


On Fri, Feb 5, 2016 at 8:26 AM, Tom Ellis <[hidden email]> wrote:
On Fri, Feb 05, 2016 at 05:25:15PM +0100, Johannes Waldmann wrote:
> > What's changed?
>
> I was referring to a discussion on ghc-devs, see
> https://mail.haskell.org/pipermail/ghc-devs/2016-February/011268.html
> and mixed up addresses when replying.

I'm glad you did, because this is the first I've heard of it!
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe


_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs




--
Chris Allen
Currently working on http://haskellbook.com

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: New type of ($) operator in GHC 8.0 is problematic

Bardur Arantsson-2
On 02/05/2016 08:05 PM, Christopher Allen wrote:
> Changing the name doesn't fix the issue. The issue is the noise and the
> referent, not the referrer. There's a habit of over-focusing on names in
> programming communities. I think it'd be a mistake to do that here and risk
> missing the point.
>

I think you're being a bit harsh, but I *do* think you're essentially
right. Beginners will have no idea what most the that means, so... *yes*
the type *will* need to be simplified for display purposes. (Unless, of
course, you opt-in to full signatures.)

Regards,

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: New type of ($) operator in GHC 8.0 is problematic

Christopher Allen
I just showed the type of ($) to my boss in our company chat who has been using Haskell for 14 years. He'd played with Haskell prior to that, but 14 years ago is when he started postgrad and teaching Haskell. Here's what he said:

>...what?
>what does that do?

He's been using Haskell in production for the last 5 years as well, I think.

Please simplify the type unless a pragma specific to levity is turned on. As it happens, I like the name levity better than runtimerep, but neither solve any pedagogical issues. YMMV.

On Fri, Feb 5, 2016 at 1:12 PM, Bardur Arantsson <[hidden email]> wrote:
On 02/05/2016 08:05 PM, Christopher Allen wrote:
> Changing the name doesn't fix the issue. The issue is the noise and the
> referent, not the referrer. There's a habit of over-focusing on names in
> programming communities. I think it'd be a mistake to do that here and risk
> missing the point.
>

I think you're being a bit harsh, but I *do* think you're essentially
right. Beginners will have no idea what most the that means, so... *yes*
the type *will* need to be simplified for display purposes. (Unless, of
course, you opt-in to full signatures.)

Regards,

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe



--
Chris Allen
Currently working on http://haskellbook.com

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: New type of ($) operator in GHC 8.0 is problematic

Tom Ellis
In reply to this post by Richard Eisenberg-2
On Fri, Feb 05, 2016 at 01:13:23PM -0500, Richard Eisenberg wrote:
> We're in a bit of a bind in all this. We really need the fancy type for
> ($) so that it can be used in all situations where it is used currently.

Is there a list of situations where ($) is used currently that give rise to
this need?
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: New type of ($) operator in GHC 8.0 is problematic

Will Yager
In reply to this post by Christopher Allen
Why must ($) be kind-polymorphic? It seems as though there is a small enough base of unboxed code that having e.g. ($#) would be fine. 

If that won't work, would it be possible to have something like

($) :: forall k a (b :: k) . (a -> b) -> a -> b

I don't know if this is possible in Haskell now, but I believe the currently popular dependently typed languages allow this sort of thing. 


> ($) :: forall (r :: RuntimeRep) (a :: *) (b :: TYPE r). (a -> b) -> a -> b


_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: New type of ($) operator in GHC 8.0 is problematic

Kyle Hanson-2
In reply to this post by Richard Eisenberg-2
Richard,

I appreciate your response and have some genuine questions about how you see the Language growing in the future. As much as I am a principled developer in terms of adhering closely to the truth as possible, I also view code as a product that needs to "customers" to be successful. In order for that to happen, it needs to easily accessible and easy to understand.

I learned Haskell almost entirely by looking at existing projects and exploring the very awesome Hackage documentation. What would be the hackage definition for ($)? Would it be `($) :: forall (r :: RuntimeRep) (a :: *) (b :: TYPE r). (a -> b) -> a -> b` with an asterisk  that says "*For beginners: ($) :: (a -> b) -> a -> b"

Would there be a "Simple Hackage"?

It would be interesting for me to see how the skill levels of Haskell are distributed. In most languages it would look like a pyramid with a small group advanced developers on top and a mountain of people underneath. Haskell seems to be pushing towards the inverse, in which to code and understand standard, non beginners mode haskell you have to be "advanced". The barrier to entry looks to be increasing.

I agree with Christopher Allen and also do not agree with your assessment and comparison to the unnecessary syntax in Java. You can explain that program using simple english. That is why it was used for so many years as an introductory language.
How do you explain `forall (r :: RuntimeRep) (a :: *) (b :: TYPE r).` using simple english?

I think its important to identify who you want your "customers" to be. If you only want the most advanced type theorists to use the language, that is perfectly fine, but what you lose are thousands of developers that can benefit the Haskell community without having to know advanced Typing. 

Needing a "Beginners" mode in a language is *not* a feature, its a fundamental design flaw. It shows that the language was not sufficiently thought out and designed for everyone.

Its extremely important to not lose touch with the people that make the community; the newcomers. Sacrificing the 99% of beginner and intermediate haskellers for the 1%, I believe is a step in the wrong direction.

--
Kyle

On Fri, Feb 5, 2016 at 10:13 AM, Richard Eisenberg <[hidden email]> wrote:
Perhaps it will aid the discussion to see that the type of ($) will, for better or worse, be changing again before 8.0.

The problem is described in GHC ticket #11471. The details of "why" aren't all that important for this discussion, but the resolution might be. The new (hopefully final!) type of ($) will be:

> ($) :: forall (r :: RuntimeRep) (a :: *) (b :: TYPE r). (a -> b) -> a -> b

Once again, it's easy enough to tweak the pretty-printer to hide the complexity. But perhaps it's not necessary. The difference as far as this conversation is concerned is that Levity has been renamed to RuntimeRep. I think this is an improvement, because now it's not terribly hard to explain:

---
1. Types of kind * have values represented by pointers. This is the vast majority of data in Haskell, because almost everything in Haskell is boxed.
2. But sometimes, we don't care how a value is represented. In this case, we can be polymorphic in the choice of representation, just like `length` is polymorphic in the choice of list element type.
3. ($) works with functions whose result can have any representation, as succinctly stated in the type. Note that the argument to the function must be boxed, however, because the implementation of ($) must store and pass the argument. It doesn't care at all about the result, though, allowing for representation-polymorphism.

In aid of this explanation, we can relate this all to Java. The reference types in Java (e.g., Object, int[], Boolean) are all like types of kind *. The primitive types in Java (int, boolean, char) do not have kind *. Java allows type abstraction (that is, generics) only over the types of kind *. Haskell is more general, allowing abstraction over primitive types via representation polymorphism.
---

Could this all be explained to a novice programmer? That would be a struggle. But it could indeed be explained to an intermediate programmer in another language just learning Haskell.

For point of comparison, Java is widely used as a teaching language. And yet one of the simplest programs is

public class HelloWorld
{
  public static void main(String[] args)
  {
    System.out.println("Hello, world!");
  }
}

When I taught Java (I taught high-school full time for 8 years), I would start with something similar to this and have to tell everyone to ignore 90% of what was written. My course never even got to arrays and `static`! That was painful, but everyone survived. This is just to point out that Haskell isn't the only language with this problem. Not to say we shouldn't try to improve!

We're in a bit of a bind in all this. We really need the fancy type for ($) so that it can be used in all situations where it is used currently. The old type for ($) was just a plain old lie. Now, at least, we're not lying. So, do we 1) lie, 2) allow the language to grow, or 3) avoid certain growth because it affects how easy the language is to learn? I don't really think anyone is advocating for (3) exactly, but it's hard to have (2) and not make things more complicated -- unless we have a beginners' mode or other features in, say, GHCi that aid learning. As I've said, I'm in full favor of adding these features.

Richard

On Feb 5, 2016, at 12:55 PM, Kyle Hanson <[hidden email]> wrote:

I am also happy the discussion was posted here. Although I don't teach Haskell professionally, one of the things I loved to do was show people how simple Haskell really was by inspecting types and slowly putting the puzzle pieces together. 

Summary of the problem for others:
From Takenobu Tani
Before ghc7.8:

  Prelude> :t foldr
  foldr :: (a -> b -> b) -> b -> [a] -> b

  Prelude> :t ($)
  ($) :: (a -> b) -> a -> b

  Beginners should only understand about following:

    * type variable (polymorphism)


After ghc8.0:

  Prelude> :t foldr
  foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b

  Prelude> :t ($)
  ($)
    :: forall (w :: GHC.Types.Levity) a (b :: TYPE w).
       (a -> b) -> a -> b


With this change it looks like I will no longer be able to keep `$` in my toolbox since telling a beginner its "magic" goes against what I believe Haskell is good at, being well defined and easy to understand (Not well defined in terms of Types but well defined in terms of ability to precisely and concisely explain and define whats going on).

It looks like where the discussion is going is to have these types show by default but eventually have an Alternative prelude for beginners.

From Richard Eisenberg:
- It's interesting that the solution to the two problems Takenobu pulls out below (but others have hinted at in this thread) is by having an alternate Prelude for beginners. I believe that having an alternate beginners' Prelude is becoming essential. I know I'm not the first one to suggest this, but a great many issues that teachers of Haskell have raised with me and posts on this and other lists would be solved by an alternate Prelude for beginners.
I don't like the idea of fragmenting Haskell into "beginners" and "advanced" versions. Its hard enough to get people to believe Haskell is easy. If they see that they aren't using the "real" prelude, Haskell will still be this magic black box that is too abstract and difficult to understand. If they have to use a "dumbed down" version of Haskell to learn, its not as compelling.

There is something powerful about using the same idiomatic tools as the "big boys" and have the tools still be able to be easy to understand.... by default. Adding complexity to the default Haskell runs the risk of further alienating newcomers to the language who have a misconception that its too hard.

Admittedly, I am not well informed of the state of GHC 8.0 development and haven't had time to fully look into the situation. I am very interested to see where this conversation and the default complexity of Haskell goes.

--
Kyle


On Fri, Feb 5, 2016 at 8:26 AM, Tom Ellis <[hidden email]> wrote:
On Fri, Feb 05, 2016 at 05:25:15PM +0100, Johannes Waldmann wrote:
> > What's changed?
>
> I was referring to a discussion on ghc-devs, see
> https://mail.haskell.org/pipermail/ghc-devs/2016-February/011268.html
> and mixed up addresses when replying.

I'm glad you did, because this is the first I've heard of it!
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe



_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: New type of ($) operator in GHC 8.0 is problematic

Marcin Mrotek
How do you explain `forall (r :: RuntimeRep) (a :: *) (b :: TYPE r).` using simple english?

"for all 'a's that are lifted types and 'b's that are types of any runtime representation 'r'..."

I don't really want to argue what is "simple english". I'd agree that Haskell's syntax is becoming more and more inadequate for expressing ideas that are being introduced to the language, though.
 
Best regards,
Marcin Mrotek

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: New type of ($) operator in GHC 8.0 is problematic

Omari Norman-2
In reply to this post by Kyle Hanson-2
On Fri, Feb 5, 2016 at 2:46 PM, Kyle Hanson <[hidden email]> wrote:
I think its important to identify who you want your "customers" to be. If you only want the most advanced type theorists to use the language, that is perfectly fine, but what you lose are thousands of developers that can benefit the Haskell community without having to know advanced Typing. 

Needing a "Beginners" mode in a language is *not* a feature, its a fundamental design flaw. It shows that the language was not sufficiently thought out and designed for everyone.

Its extremely important to not lose touch with the people that make the community; the newcomers. Sacrificing the 99% of beginner and intermediate haskellers for the 1%, I believe is a step in the wrong direction.


I'm sympathetic, but the same arguments were made against the Foldable-Traversable Proposal. See for instance


Since that wound up going in, I think this ship has sailed.  Types are going to become increasingly polymorphic in the Prelude.  Though I wish this weren't so I've come to accept it, and I doubt attacking it head on is going to get anywhere.
 

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: New type of ($) operator in GHC 8.0 is problematic

Mike Izbicki
In reply to this post by Richard Eisenberg-2
> We're in a bit of a bind in all this. We really need the fancy type for ($)
> so that it can be used in all situations where it is used currently. The old
> type for ($) was just a plain old lie. Now, at least, we're not lying. So,
> do we 1) lie, 2) allow the language to grow, or 3) avoid certain growth
> because it affects how easy the language is to learn? I don't really think
> anyone is advocating for (3) exactly, but it's hard to have (2) and not make
> things more complicated -- unless we have a beginners' mode or other
> features in, say, GHCi that aid learning. As I've said, I'm in full favor of
> adding these features.

The old type for ($) is only a lie when the MagicHash extension is
turned on.  Otherwise, it is not a lie.  I think the best solution is
to pretty print the type depending on what language pragmas are in
use.  In GHCI, this would be trivial.  The much harder case is haddock
documentation.

I think a good way around this would be an eventual patch to haddock
that allows the user to select which extensions they want to use when
browsing documentation.  There's a lot of usability issues that would
need to be resolved with this still, but it reduces this technical
discussion we're having down to a design discussion.  It also nicely
lets the user specify the level of difficulty they want their prelude
to be without causing incompatibilty with users who want a different
level of prelude.
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: New type of ($) operator in GHC 8.0 is problematic

Imants Cekusins
off-topic but still may be relevant. my apologies if it isn't:

isn't a good programming language - simple and unambiguous?

isn't programming language as much about communicating with other
programmers as about instructing compiler?

look at the game of chess: limited number of clear rules allow for
many complex and rich games.

clarity, convenience + library coverage would draw users and keep
them, I think. Good shiny tools attract interest. However it's what
you could make with these tools matters.
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Language complexity & beginners (Was: New type of ($) operator in GHC 8.0 is problematic)

Richard Eisenberg-2
In reply to this post by Christopher Allen
It may come as a surprise to many of you that I, too, am very worried about Haskell becoming inaccessible to newcomers. If we can't induct new people into our ranks, we will die. It is for this reason that I have always been unhappy with the FTP. But that ship has sailed.

I fully agree with George's suggestion below that the default Prelude should be the beginner's Prelude. I believe I have argued this stance in the past, but louder voices prevailed. Perhaps I was wrong in branding: we should have a proper Prelude as the default, and make available a super whiz-bang advanced Prelude as well. I'm never very good about branding. I'd lend strong support to someone who articulates a concrete move in this direction, but I don't have the bandwidth to spearhead it myself.

Despite the various arguments saying that the bits in Java are easier to understand than the bits in ($), I'm quite unconvinced. (Particularly about `static`. Even `class` is hard for true beginners.) And the boxed/unboxed distinction does come up early in Java: just try to write an ArrayList<int> and now you need to know about boxed types and unboxed ones.

Chris's point that "it's not about the name" is valid. The Levity --> RuntimeRep change is not about the name, but about the functionality. Levity distinguished only between lifted and unlifted; RuntimeRep distinguishes between boxed/lifted, boxed/unlifted, and all the unboxed types with their different widths. I'm just clarifying that it's not simply a cosmetic name-change. 

The old type of ($) was always a lie. -XMagicHash just changes the parser, allowing the # suffix. It is only by convention that most (all?) unlifted things end in #. The old type of ($) was perhaps a harmless lie, but a lie nonetheless.

Are we comfortable with lying? (Believe me, I'm not trying to impose some moral dimension to simplifying output!) In my mind, lying about types like this is in the same space as having a beginner's Prelude. And people will constantly discover that we're lying and get very confused. Having a whole host of flags that tell GHC to lie less is somewhat like having two versions of the language... only the differences manifest only in output instead of input.

If we are comfortable with lying in this way: as I've offered, I can hide the type of ($) (and other representation-polymorphic things) behind a flag. Easy to do.

Another great question that has come up is about Haddock output (Hackage). I think Haddock needs to add a facility where library authors can include specializations of an overly general type. This can be done in commentary, but it's not as prominent. Such a new feature would address the ($) problem, as ($) :: forall (a :: *) (b :: *). (a -> b) -> a -> b is a specialization of its real type. It would also help a great deal with FTP-related generalizations.

I also want to respond directly to Kyle's comments:

I think its important to identify who you want your "customers" to be. If you only want the most advanced type theorists to use the language, that is perfectly fine, but what you lose are thousands of developers that can benefit the Haskell community without having to know advanced Typing. 

Rest assured, I want my "customers" to be everyone who wants to program. I've volunteered to teach a bit of Haskell to high schoolers, and I'd love a shot at a course where I teach it to people who have never programmed.


Needing a "Beginners" mode in a language is *not* a feature, its a fundamental design flaw. It shows that the language was not sufficiently thought out and designed for everyone.

On an intuitive level, this rings true for me. But when I think about the details, I'm less convinced. For example, take Scratch (scratch.mit.edu), which is wonderfully easy to learn and gives kids (and adults!) a great deal of fun. Yet it's painful to use when you know more. And the Racket folks have invested a lot of time in coming up with a curriculum to go with their language, and they explicitly have expertise levels. Needing these levels may just be part of the game.

So, rest assured, I remain very receptive to these concerns. And I'd love concrete help in putting them to rest.

Richard


On Feb 5, 2016, at 6:30 PM, George Colpitts <[hidden email]> wrote:

+1 for Christopher's email
Richard, I disagree with  "But it could indeed be explained to an intermediate programmer in another language just learning Haskell." Your explanation is good but it assumes you have already explained "types of kind *" and the boxed vs unboxed distinction. Admittedly the latter should be understood by most Java programmers but I doubt that intermediate programmers in other languages do. If I did have to explain "$" I would say, for now think of it in terms of it's pre 8.0 type. Alternatively avoid mentioning "$" to beginners. I don't believe it is in Hutton's book or any of Bird's although I might be wrong.

Most intermediate programmers in another language struggle a lot with learning monads, witness all the monad tutorials. Absorbing monads is central, there is a lot that has to be explained before that. Minimizing that material would be a good thing. 

I have mixed feelings about a beginner's prelude best summarized by saying the proposed beginner's prelude should be the standard prelude and the current one should be an advanced prelude. If we have a beginner's prelude I feel we are saying that this is a hard to understand research language and we hope that someday you have enough education, energy and tenacity to get to the point where you understand it. If we do it the other way we are saying you have what you need but if you want more there is lots!

On Fri, Feb 5, 2016 at 3:05 PM, Christopher Allen <[hidden email]> wrote:
Changing the name doesn't fix the issue. The issue is the noise and the referent, not the referrer. There's a habit of over-focusing on names in programming communities. I think it'd be a mistake to do that here and risk missing the point.

You can make all of the keywords in the Java example salient early on, but you cannot make the implementation details you're exposing in the type of ($) relevant unless they already have a year or two of Haskell under their belts. Listing out the keywords:

1. public

2. class

3. (class name)

4. static

5. void

6. (method name)

7. (method arguments)

Explaining public, class, static, and void usually happens pretty soon after the basics in a Java course. Importantly, they're things you _need_ to know to get things done properly in Java. The same is not true of what is mentioned in the type of ($).

The implicit prenex form and forall are irrelevant for learners until they get to Rank2/RankN which is very much beyond, "I am learning Haskell" and into, "I am designing an API in Haskell for other people to use". * vs. # is something many working and hobbyist Haskellers I've known will scarcely know anything about.

There is a big difference, to my mind, between what is being exposed here in Java versus what is being exposed in the type ($). Consider that the boxed/unboxed distinction exists in Java but needn't come up in any beginner tutorials.

>Types of kind * have values represented by pointers. This is the vast majority of data in Haskell, because almost everything in Haskell is boxed.

We can't assume Haskell learners know what pointers are. This, again, creates unnecessary noise for learners by forcing exposure to things that are irrelevant for a very long time.


On Fri, Feb 5, 2016 at 12:13 PM, Richard Eisenberg <[hidden email]> wrote:
Perhaps it will aid the discussion to see that the type of ($) will, for better or worse, be changing again before 8.0.

The problem is described in GHC ticket #11471. The details of "why" aren't all that important for this discussion, but the resolution might be. The new (hopefully final!) type of ($) will be:

> ($) :: forall (r :: RuntimeRep) (a :: *) (b :: TYPE r). (a -> b) -> a -> b

Once again, it's easy enough to tweak the pretty-printer to hide the complexity. But perhaps it's not necessary. The difference as far as this conversation is concerned is that Levity has been renamed to RuntimeRep. I think this is an improvement, because now it's not terribly hard to explain:

---
1. Types of kind * have values represented by pointers. This is the vast majority of data in Haskell, because almost everything in Haskell is boxed.
2. But sometimes, we don't care how a value is represented. In this case, we can be polymorphic in the choice of representation, just like `length` is polymorphic in the choice of list element type.
3. ($) works with functions whose result can have any representation, as succinctly stated in the type. Note that the argument to the function must be boxed, however, because the implementation of ($) must store and pass the argument. It doesn't care at all about the result, though, allowing for representation-polymorphism.

In aid of this explanation, we can relate this all to Java. The reference types in Java (e.g., Object, int[], Boolean) are all like types of kind *. The primitive types in Java (int, boolean, char) do not have kind *. Java allows type abstraction (that is, generics) only over the types of kind *. Haskell is more general, allowing abstraction over primitive types via representation polymorphism.
---

Could this all be explained to a novice programmer? That would be a struggle. But it could indeed be explained to an intermediate programmer in another language just learning Haskell.

For point of comparison, Java is widely used as a teaching language. And yet one of the simplest programs is

public class HelloWorld
{
  public static void main(String[] args)
  {
    System.out.println("Hello, world!");
  }
}

When I taught Java (I taught high-school full time for 8 years), I would start with something similar to this and have to tell everyone to ignore 90% of what was written. My course never even got to arrays and `static`! That was painful, but everyone survived. This is just to point out that Haskell isn't the only language with this problem. Not to say we shouldn't try to improve!

We're in a bit of a bind in all this. We really need the fancy type for ($) so that it can be used in all situations where it is used currently. The old type for ($) was just a plain old lie. Now, at least, we're not lying. So, do we 1) lie, 2) allow the language to grow, or 3) avoid certain growth because it affects how easy the language is to learn? I don't really think anyone is advocating for (3) exactly, but it's hard to have (2) and not make things more complicated -- unless we have a beginners' mode or other features in, say, GHCi that aid learning. As I've said, I'm in full favor of adding these features.

Richard

On Feb 5, 2016, at 12:55 PM, Kyle Hanson <[hidden email]> wrote:

I am also happy the discussion was posted here. Although I don't teach Haskell professionally, one of the things I loved to do was show people how simple Haskell really was by inspecting types and slowly putting the puzzle pieces together. 

Summary of the problem for others:
From Takenobu Tani
Before ghc7.8:

  Prelude> :t foldr
  foldr :: (a -> b -> b) -> b -> [a] -> b

  Prelude> :t ($)
  ($) :: (a -> b) -> a -> b

  Beginners should only understand about following:

    * type variable (polymorphism)


After ghc8.0:

  Prelude> :t foldr
  foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b

  Prelude> :t ($)
  ($)
    :: forall (w :: GHC.Types.Levity) a (b :: TYPE w).
       (a -> b) -> a -> b


With this change it looks like I will no longer be able to keep `$` in my toolbox since telling a beginner its "magic" goes against what I believe Haskell is good at, being well defined and easy to understand (Not well defined in terms of Types but well defined in terms of ability to precisely and concisely explain and define whats going on).

It looks like where the discussion is going is to have these types show by default but eventually have an Alternative prelude for beginners.

From Richard Eisenberg:
- It's interesting that the solution to the two problems Takenobu pulls out below (but others have hinted at in this thread) is by having an alternate Prelude for beginners. I believe that having an alternate beginners' Prelude is becoming essential. I know I'm not the first one to suggest this, but a great many issues that teachers of Haskell have raised with me and posts on this and other lists would be solved by an alternate Prelude for beginners.
I don't like the idea of fragmenting Haskell into "beginners" and "advanced" versions. Its hard enough to get people to believe Haskell is easy. If they see that they aren't using the "real" prelude, Haskell will still be this magic black box that is too abstract and difficult to understand. If they have to use a "dumbed down" version of Haskell to learn, its not as compelling.

There is something powerful about using the same idiomatic tools as the "big boys" and have the tools still be able to be easy to understand.... by default. Adding complexity to the default Haskell runs the risk of further alienating newcomers to the language who have a misconception that its too hard.

Admittedly, I am not well informed of the state of GHC 8.0 development and haven't had time to fully look into the situation. I am very interested to see where this conversation and the default complexity of Haskell goes.

--
Kyle


On Fri, Feb 5, 2016 at 8:26 AM, Tom Ellis <[hidden email]> wrote:
On Fri, Feb 05, 2016 at 05:25:15PM +0100, Johannes Waldmann wrote:
> > What's changed?
>
> I was referring to a discussion on ghc-devs, see
> https://mail.haskell.org/pipermail/ghc-devs/2016-February/011268.html
> and mixed up addresses when replying.

I'm glad you did, because this is the first I've heard of it!
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe


_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs




--
Chris Allen
Currently working on http://haskellbook.com

_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs




_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Language complexity & beginners (Was: New type of ($) operator in GHC 8.0 is problematic)

Mihai Maruseac
On Fri, Feb 5, 2016 at 7:09 PM, Richard Eisenberg <[hidden email]> wrote:
>
> Another great question that has come up is about Haddock output (Hackage). I
> think Haddock needs to add a facility where library authors can include
> specializations of an overly general type. This can be done in commentary,
> but it's not as prominent. Such a new feature would address the ($) problem,
> as ($) :: forall (a :: *) (b :: *). (a -> b) -> a -> b is a specialization
> of its real type. It would also help a great deal with FTP-related
> generalizations.


This goes hand in hand with Artyom's suggestion of a warning in GHCi
after showing the simpler type.

I'm thinking of a flag which enables/disables printing the simplest
type with warning (in GHCi) or footnote (or otherwise, in Haddock). We
can have the default behavior of the flag be either printing the
simpler type + extra (warning/footnote) or printing the longer type
and include a reference in our learning materials that beginners and
people confused by the long, complex and real type, can use
--use-simpler-types flag.

--
Mihai Maruseac (MM)
"If you can't solve a problem, then there's an easier problem you can
solve: find it." -- George Polya
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Language complexity & beginners (Was: New type of ($) operator in GHC 8.0 is problematic)

Takenobu Tani
In reply to this post by Richard Eisenberg-2
Hi,

I tried to draw informal illustrations about Foldable signatures for beginners [1].
I'll also try to draw simple illustrations about new ($).

Of course I like Haskell's beautiful abstraction :)
Thank you for your great efforts.


Regards,
Takenobu


2016-02-06 9:09 GMT+09:00 Richard Eisenberg <[hidden email]>:
It may come as a surprise to many of you that I, too, am very worried about Haskell becoming inaccessible to newcomers. If we can't induct new people into our ranks, we will die. It is for this reason that I have always been unhappy with the FTP. But that ship has sailed.

I fully agree with George's suggestion below that the default Prelude should be the beginner's Prelude. I believe I have argued this stance in the past, but louder voices prevailed. Perhaps I was wrong in branding: we should have a proper Prelude as the default, and make available a super whiz-bang advanced Prelude as well. I'm never very good about branding. I'd lend strong support to someone who articulates a concrete move in this direction, but I don't have the bandwidth to spearhead it myself.

Despite the various arguments saying that the bits in Java are easier to understand than the bits in ($), I'm quite unconvinced. (Particularly about `static`. Even `class` is hard for true beginners.) And the boxed/unboxed distinction does come up early in Java: just try to write an ArrayList<int> and now you need to know about boxed types and unboxed ones.

Chris's point that "it's not about the name" is valid. The Levity --> RuntimeRep change is not about the name, but about the functionality. Levity distinguished only between lifted and unlifted; RuntimeRep distinguishes between boxed/lifted, boxed/unlifted, and all the unboxed types with their different widths. I'm just clarifying that it's not simply a cosmetic name-change. 

The old type of ($) was always a lie. -XMagicHash just changes the parser, allowing the # suffix. It is only by convention that most (all?) unlifted things end in #. The old type of ($) was perhaps a harmless lie, but a lie nonetheless.

Are we comfortable with lying? (Believe me, I'm not trying to impose some moral dimension to simplifying output!) In my mind, lying about types like this is in the same space as having a beginner's Prelude. And people will constantly discover that we're lying and get very confused. Having a whole host of flags that tell GHC to lie less is somewhat like having two versions of the language... only the differences manifest only in output instead of input.

If we are comfortable with lying in this way: as I've offered, I can hide the type of ($) (and other representation-polymorphic things) behind a flag. Easy to do.

Another great question that has come up is about Haddock output (Hackage). I think Haddock needs to add a facility where library authors can include specializations of an overly general type. This can be done in commentary, but it's not as prominent. Such a new feature would address the ($) problem, as ($) :: forall (a :: *) (b :: *). (a -> b) -> a -> b is a specialization of its real type. It would also help a great deal with FTP-related generalizations.

I also want to respond directly to Kyle's comments:

I think its important to identify who you want your "customers" to be. If you only want the most advanced type theorists to use the language, that is perfectly fine, but what you lose are thousands of developers that can benefit the Haskell community without having to know advanced Typing. 

Rest assured, I want my "customers" to be everyone who wants to program. I've volunteered to teach a bit of Haskell to high schoolers, and I'd love a shot at a course where I teach it to people who have never programmed.


Needing a "Beginners" mode in a language is *not* a feature, its a fundamental design flaw. It shows that the language was not sufficiently thought out and designed for everyone.

On an intuitive level, this rings true for me. But when I think about the details, I'm less convinced. For example, take Scratch (scratch.mit.edu), which is wonderfully easy to learn and gives kids (and adults!) a great deal of fun. Yet it's painful to use when you know more. And the Racket folks have invested a lot of time in coming up with a curriculum to go with their language, and they explicitly have expertise levels. Needing these levels may just be part of the game.

So, rest assured, I remain very receptive to these concerns. And I'd love concrete help in putting them to rest.

Richard


On Feb 5, 2016, at 6:30 PM, George Colpitts <[hidden email]> wrote:

+1 for Christopher's email
Richard, I disagree with  "But it could indeed be explained to an intermediate programmer in another language just learning Haskell." Your explanation is good but it assumes you have already explained "types of kind *" and the boxed vs unboxed distinction. Admittedly the latter should be understood by most Java programmers but I doubt that intermediate programmers in other languages do. If I did have to explain "$" I would say, for now think of it in terms of it's pre 8.0 type. Alternatively avoid mentioning "$" to beginners. I don't believe it is in Hutton's book or any of Bird's although I might be wrong.

Most intermediate programmers in another language struggle a lot with learning monads, witness all the monad tutorials. Absorbing monads is central, there is a lot that has to be explained before that. Minimizing that material would be a good thing. 

I have mixed feelings about a beginner's prelude best summarized by saying the proposed beginner's prelude should be the standard prelude and the current one should be an advanced prelude. If we have a beginner's prelude I feel we are saying that this is a hard to understand research language and we hope that someday you have enough education, energy and tenacity to get to the point where you understand it. If we do it the other way we are saying you have what you need but if you want more there is lots!

On Fri, Feb 5, 2016 at 3:05 PM, Christopher Allen <[hidden email]> wrote:
Changing the name doesn't fix the issue. The issue is the noise and the referent, not the referrer. There's a habit of over-focusing on names in programming communities. I think it'd be a mistake to do that here and risk missing the point.

You can make all of the keywords in the Java example salient early on, but you cannot make the implementation details you're exposing in the type of ($) relevant unless they already have a year or two of Haskell under their belts. Listing out the keywords:

1. public

2. class

3. (class name)

4. static

5. void

6. (method name)

7. (method arguments)

Explaining public, class, static, and void usually happens pretty soon after the basics in a Java course. Importantly, they're things you _need_ to know to get things done properly in Java. The same is not true of what is mentioned in the type of ($).

The implicit prenex form and forall are irrelevant for learners until they get to Rank2/RankN which is very much beyond, "I am learning Haskell" and into, "I am designing an API in Haskell for other people to use". * vs. # is something many working and hobbyist Haskellers I've known will scarcely know anything about.

There is a big difference, to my mind, between what is being exposed here in Java versus what is being exposed in the type ($). Consider that the boxed/unboxed distinction exists in Java but needn't come up in any beginner tutorials.

>Types of kind * have values represented by pointers. This is the vast majority of data in Haskell, because almost everything in Haskell is boxed.

We can't assume Haskell learners know what pointers are. This, again, creates unnecessary noise for learners by forcing exposure to things that are irrelevant for a very long time.


On Fri, Feb 5, 2016 at 12:13 PM, Richard Eisenberg <[hidden email]> wrote:
Perhaps it will aid the discussion to see that the type of ($) will, for better or worse, be changing again before 8.0.

The problem is described in GHC ticket #11471. The details of "why" aren't all that important for this discussion, but the resolution might be. The new (hopefully final!) type of ($) will be:

> ($) :: forall (r :: RuntimeRep) (a :: *) (b :: TYPE r). (a -> b) -> a -> b

Once again, it's easy enough to tweak the pretty-printer to hide the complexity. But perhaps it's not necessary. The difference as far as this conversation is concerned is that Levity has been renamed to RuntimeRep. I think this is an improvement, because now it's not terribly hard to explain:

---
1. Types of kind * have values represented by pointers. This is the vast majority of data in Haskell, because almost everything in Haskell is boxed.
2. But sometimes, we don't care how a value is represented. In this case, we can be polymorphic in the choice of representation, just like `length` is polymorphic in the choice of list element type.
3. ($) works with functions whose result can have any representation, as succinctly stated in the type. Note that the argument to the function must be boxed, however, because the implementation of ($) must store and pass the argument. It doesn't care at all about the result, though, allowing for representation-polymorphism.

In aid of this explanation, we can relate this all to Java. The reference types in Java (e.g., Object, int[], Boolean) are all like types of kind *. The primitive types in Java (int, boolean, char) do not have kind *. Java allows type abstraction (that is, generics) only over the types of kind *. Haskell is more general, allowing abstraction over primitive types via representation polymorphism.
---

Could this all be explained to a novice programmer? That would be a struggle. But it could indeed be explained to an intermediate programmer in another language just learning Haskell.

For point of comparison, Java is widely used as a teaching language. And yet one of the simplest programs is

public class HelloWorld
{
  public static void main(String[] args)
  {
    System.out.println("Hello, world!");
  }
}

When I taught Java (I taught high-school full time for 8 years), I would start with something similar to this and have to tell everyone to ignore 90% of what was written. My course never even got to arrays and `static`! That was painful, but everyone survived. This is just to point out that Haskell isn't the only language with this problem. Not to say we shouldn't try to improve!

We're in a bit of a bind in all this. We really need the fancy type for ($) so that it can be used in all situations where it is used currently. The old type for ($) was just a plain old lie. Now, at least, we're not lying. So, do we 1) lie, 2) allow the language to grow, or 3) avoid certain growth because it affects how easy the language is to learn? I don't really think anyone is advocating for (3) exactly, but it's hard to have (2) and not make things more complicated -- unless we have a beginners' mode or other features in, say, GHCi that aid learning. As I've said, I'm in full favor of adding these features.

Richard

On Feb 5, 2016, at 12:55 PM, Kyle Hanson <[hidden email]> wrote:

I am also happy the discussion was posted here. Although I don't teach Haskell professionally, one of the things I loved to do was show people how simple Haskell really was by inspecting types and slowly putting the puzzle pieces together. 

Summary of the problem for others:
From Takenobu Tani
Before ghc7.8:

  Prelude> :t foldr
  foldr :: (a -> b -> b) -> b -> [a] -> b

  Prelude> :t ($)
  ($) :: (a -> b) -> a -> b

  Beginners should only understand about following:

    * type variable (polymorphism)


After ghc8.0:

  Prelude> :t foldr
  foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b

  Prelude> :t ($)
  ($)
    :: forall (w :: GHC.Types.Levity) a (b :: TYPE w).
       (a -> b) -> a -> b


With this change it looks like I will no longer be able to keep `$` in my toolbox since telling a beginner its "magic" goes against what I believe Haskell is good at, being well defined and easy to understand (Not well defined in terms of Types but well defined in terms of ability to precisely and concisely explain and define whats going on).

It looks like where the discussion is going is to have these types show by default but eventually have an Alternative prelude for beginners.

From Richard Eisenberg:
- It's interesting that the solution to the two problems Takenobu pulls out below (but others have hinted at in this thread) is by having an alternate Prelude for beginners. I believe that having an alternate beginners' Prelude is becoming essential. I know I'm not the first one to suggest this, but a great many issues that teachers of Haskell have raised with me and posts on this and other lists would be solved by an alternate Prelude for beginners.
I don't like the idea of fragmenting Haskell into "beginners" and "advanced" versions. Its hard enough to get people to believe Haskell is easy. If they see that they aren't using the "real" prelude, Haskell will still be this magic black box that is too abstract and difficult to understand. If they have to use a "dumbed down" version of Haskell to learn, its not as compelling.

There is something powerful about using the same idiomatic tools as the "big boys" and have the tools still be able to be easy to understand.... by default. Adding complexity to the default Haskell runs the risk of further alienating newcomers to the language who have a misconception that its too hard.

Admittedly, I am not well informed of the state of GHC 8.0 development and haven't had time to fully look into the situation. I am very interested to see where this conversation and the default complexity of Haskell goes.

--
Kyle


On Fri, Feb 5, 2016 at 8:26 AM, Tom Ellis <[hidden email]> wrote:
On Fri, Feb 05, 2016 at 05:25:15PM +0100, Johannes Waldmann wrote:
> > What's changed?
>
> I was referring to a discussion on ghc-devs, see
> https://mail.haskell.org/pipermail/ghc-devs/2016-February/011268.html
> and mixed up addresses when replying.

I'm glad you did, because this is the first I've heard of it!
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe


_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs




--
Chris Allen
Currently working on http://haskellbook.com

_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs




_______________________________________________
ghc-devs mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/ghc-devs



_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
1234 ... 8