问题
Before Haskell 98, there were Haskell 1.0 through 1.4. It's pretty interesting to see the development throughout the years, as features were added to the earliest versions of standardized Haskell.
For instance, the do-notation was first standardized by Haskell 1.3 (published 1996-05-01). In the Prelude
, we find the following definitions (page 87):
-- Monadic classes
class Functor f where
map :: (a -> b) -> f a -> f b
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
return :: a -> m a
m >> k = m >>= \_ -> k
class (Monad m) => MonadZero m where
zero :: m a
class (MonadZero m) => MonadPlus m where
(++) :: m a -> m a -> m a
The same definitions are found in Haskell 1.4. I do have a few problems with this (e.g. the MonadPlus reform hasn't happened here yet), but overall, it is a very nice definition.
This is very different from Haskell 98, where the following definition is found:
-- Monadic classes
class Functor f where
fmap :: (a -> b) -> f a -> f b
class Monad m where
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
return :: a -> m a
fail :: String -> m a
-- Minimal complete definition:
-- (>>=), return
m >> k = m >>= \_ -> k
fail s = error s
This is also the definition in Haskell 2010. I have the following problems with this definition:
MonadZero
andMonadPlus
are gone. They were useful classes.In case of a pattern match failure in a do-notation...
- Haskell 1.3 uses
zero
. The Left Zero law applies (zero >>= k = zero
), so you know what's supposed to happen. - Haskell 98 uses
fail msg
, wheremsg
is compiler-generated in case of GHC. Anything can happen, no guarantees about its semantics. Therefore, it's not much of a function for users. As a consequence, the behaviour of pattern match failures in Haskell 98's do-notation is unpredictable!
- Haskell 1.3 uses
Names are less general (e.g.
map
vs.fmap
). Not a big problem, but it's a thorn in my eye.
All in all, I think these changes weren't for the best. In fact, I think they were a step backwards from Haskell 1.4. Why were these things changed for Haskell 98, and why in this way?
As an aside, I can imagine the following defenses:
- "
fail
allows for locating errors." Only for programmers, and only at runtime. The (unportable!) error message is not exactly something you want to parse. If you really care about it, you should track it explicitly. We now haveControl.Failure
from thefailure
package, which does a much better job at this (failure x
behaves mostly likezero
). - "Having too many classes makes development and use too hard." Having too few classes breaks their laws, and those laws are just as important as types.
- "Instance-restricted functions are easier to learn." Then why isn't there a
SimplePrelude
instead, with most of the classes removed? It's only one magical declaration away for students, they can manage that much. (Perhaps{-# LANGUAGE RebindableSyntax #-}
is needed too, but again, students are very good at copy-pasting stuff.) - "Instance-restricted functions make errors more readable." I use
fmap
much more often thanmap
, so why notmap
andlistMap
instead?
回答1:
Why were these things changed for Haskell 98, and why in this way?
Haskell 98 involves a lot of simplification to the language (much of which has since been reversed). The goal was to improve Haskell as a teaching language, and to make relatively conservative choices.
See e.g.
We regarded Haskell 98 as a reasonably conservative design. For example, by that time multi-parameter type classes were being widely used, but Haskell 98 only has single-parameter type classes (Peyton Jones et al., 1997).
In: History of Haskell
And:
Haskell 98 will by no means be the last revision of Haskell. On the contrary, we design it knowing that new language extensions (multi-parameter type classes, universal and existential quantification, pattern guards, etc, etc) are well on the way. However, Haskell 98 will have a special status: the intention is that Haskell compilers will continue to support Haskell 98 (given an appropriate flag) even after later versions of the language have been defined, and so the name `Haskell 98' will refer to a fixed, stable language.
In: Haskell98 report
So, things were simplified, with the goal of producing a simpler standard.
来源:https://stackoverflow.com/questions/18761302/why-were-haskell-98s-standard-classes-made-inferior-to-haskell-1-3s