String != [Char]

Greg Weber greg at
Sun Mar 25 04:09:59 CEST 2012

# Switching to Text by default makes us embarrassed!

Problem: we want to write beautiful (and possibly inefficient) code
that is easy to explain. If nothing else, this is pedagologically
The goals of this code are to:
  * use list processing pattern matching and functions on a string type
  * avoid embarassing name clashes and the need for qualified names
(T.split, etc)

The second point is Haskell's festering language design sore rearing
its ugly head.
Lets note that the current state of Haskell is not any more beautiful
than what will happen after this proposal is implemented. It is just
that we currently have partly hidden away a deficiency in Haskell by
only exporting list functions in the Prelude. So our real goal is to
come up with conventions and/or hacks that will allow us to continue
to hide this deficiency of Haskell for the purposes of pedagogy.
If you can't tell, IMHO the issue we are circumventing is Haskell's
biggest issue form a laguage design perspective. It is a shame that
SPJ's TDNR proposal was shouted down and no alternative has been

But I am not going to hold out hope that this issue will be solved any
time soon. Just limiting solving this to records has proved very
difficult. So onto our hacks for making Text the default string type!

## Option 1: T. prefixing

using Text functions still requires the T. prefix
For pedagogy, continue to use [Char], but use an OverloadedText extension

This is a safe conservative option that puts us in a better place than
we are today.
It just makes us look strange when we build something into the
language that requires a prefix.
Of course, we could try to give every Text function a slightly
different name than the Prelude list functions, but I think that will
make using Haskell more difficult that putting up with prefixes.

## Option 2: TDNR for lists

(Prelude) list functions are resolved in a special way.
For example, we could have 2 different map functions in scope
unqualified: one for lists, and one for Text. The compiler is tasked
with resolving whether the type is a list or not and determining the
appropriate function.

I would much rather add a TDNR construct to the language in a
universal way than go down this route.

## Option 3: implicit List typeclass

We can operate on Text (and other non-list data structures) using a
List typeclass.
We have 2 concers:
  * list pattern matching ('c':string)
  * requiring the typeclass in the type signature everywhere

I think we can extend the compiler to pattern match characters out of
Text, so lets move onto the second point.
If we don't write type signatures anywhere, we actually won't care about it.
However, if we add sparse annotations, we will need a List constraint.

  listF :: List l => ...

This could get tiresome quickly. It makes pedagogy immediately delve
into an explanation of typeclasses. A simple solution is to special
case the List class.
We declare that List is so fundamental to Haskell that requiring the
List typeclass is not necessary.
The Prelude exports (class List where ...).
If a List typeclass function is used, the compiler inserts the List
typeclass constraint into a type signature automatically.

This option is very attractive because it solves all of our problems
at the cost of 1 easy to explain piece of magic. It also makes it
possible to unify list behavior across different data types without
the hassle of typeclass insertions everywhere.

More information about the Haskell-prime mailing list