Подтвердить что ты не робот

Почему стандартные классы Haskell 98 уступают Haskell 1.3?

До Haskell 98 были Haskell с 1.0 по 1.4. Очень интересно видеть развитие на протяжении многих лет, поскольку функции были добавлены к ранним версиям стандартизованного Haskell.

Например, предварительная нотация была сначала стандартизирована Haskell 1.3 (опубликовано в 1996-05-01). В Prelude мы находим следующие определения (стр. 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

Те же определения найдены в Haskell 1.4. У меня есть несколько проблем с этим (например, MonadPlus reform здесь еще не произошло), но в целом, это очень приятно определение.

Это сильно отличается от Haskell 98, где найдено следующее определение:

-- 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

Это также определение в Haskell 2010. У меня есть следующие проблемы с этим определением:

  • MonadZero и MonadPlus исчезли. Они были полезными классами.
  • В случае неудачи совпадения шаблона в do-notation...

    • В Haskell 1.3 используется zero. Закон Левого нуля применяется (zero >>= k = zero), поэтому вы знаете, что должно произойти.
    • Haskell 98 использует fail msg, где msg генерируется компилятором в случае GHC. Все может случиться, никаких гарантий относительно его семантики. Поэтому он не очень удобен для пользователей. Как следствие, поведение неудачных совпадений шаблонов в служебной записи Haskell 98 непредсказуемо!
  • Имена менее общие (например, map vs. fmap). Не большая проблема, но это шип в моих глазах.


В целом, я думаю, что эти изменения были не самыми лучшими. На самом деле, я думаю, что они были шагом назад от Haskell 1.4. Почему эти вещи изменились для Haskell 98 и почему так?


В стороне, я могу представить себе следующую защиту:

  • "fail позволяет обнаруживать ошибки". Только для программистов и только во время выполнения. Сообщение об ошибке (unportable!) - это не то, что вы хотите проанализировать. Если вы действительно заботитесь об этом, вы должны отслеживать это явно. Теперь у нас есть Control.Failure из пакета failure, который намного лучше работает (failure x ведет себя в основном как zero).
  • "Слишком много классов делает разработку и использует слишком много". Слишком мало классов нарушает их законы, и эти законы так же важны, как и типы.
  • "Функции с ограниченным доступом легче изучить". Тогда почему нет SimplePrelude, а большинство классов удалено? Это только одна магическая декларация для студентов, они могут так много обойтись. (Возможно, требуется и {-# LANGUAGE RebindableSyntax #-}, но опять же, студенты очень хорошо разбираются в копировании).
  • "Ограниченные экземпляром функции делают ошибки более читабельными". Я использую fmap гораздо чаще, чем map, так почему бы не map и listMap вместо?
4b9b3361

Ответ 1

Почему эти вещи изменились для Haskell 98 и почему так?

Haskell 98 включает в себя много упрощения языка (большая часть которого с тех пор была отменена). Цель состояла в том, чтобы улучшить Haskell в качестве учебного языка и сделать относительно консервативный выбор.

См., например,

Мы рассматривали Haskell 98 как достаточно консервативный дизайн. Для Например, к этому времени многопараметрические типы классов широко, но Haskell 98 имеет только классы с одним параметром (Peyton Jones et al., 1997).

В: История Haskell

и

Haskell 98 ни в коем случае не будет последней версией Haskell. На напротив, мы разрабатываем его, зная, что новые языковые расширения (классы с несколькими параметрами, универсальные и экзистенциальные количественная оценка, ограждения рисунков и т.д. и т.д.). Однако Haskell 98 будет иметь особый статус: предполагается, что Компиляторы Haskell будут продолжать поддерживать Haskell 98 (учитывая соответствующий флаг) даже после того, как более поздние версии языка были и поэтому имя "Haskell 98" будет ссылаться на фиксированную, стабильную язык.

В: отчет Haskell98

Итак, все упростилось, с целью создания более простого стандарта.