为什么Haskell 98的标准类不如Haskell 1.3? [英] Why were Haskell 98's standard classes made inferior to Haskell 1.3's?

查看:131
本文介绍了为什么Haskell 98的标准类不如Haskell 1.3?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在Haskell 98之前,有Haskell 1.0到1.4。看到这些年来的发展非常有趣,因为功能被添加到了最早版本的标准化Haskell中。

例如,标记首先由< a href =http://www.haskell.org/definition/haskell-report-1.3.ps.gz =nofollow> Haskell 1.3 (1996-05-01出版)。在 Prelude 中,我们找到了下列定义(第87页):

   - 一元类

类Functor f其中
map ::(a - > b) - > f a - > f b

class Monad m其中
(>> =):: 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其中
zero :: m a

class(MonadZero m)=> MonadPlus m其中
(++):: m a - > m a - > m

Haskell 1.4中提供了相同的定义。我确实遇到了一些问题(例如 MonadPlus 改革在这里还没有发生),但总体而言,这是一个非常好的定义。



这与Haskell 98非常不同,后者的定义如下找到:

   -  Monadic类


类Functor f其中
fmap ::(a - > b) - > f a - > f b


class Monad m其中
(>> =):: m a - > (a - > m b) - > m b
(>>):: m a - > m b - > m b
return :: a - > m a
fail :: String - > m a

- 最小完整定义:
- (>> =),返回
m>> k = m>> = \\ __ - > k
失败s =错误s

这也是Haskell 2010中的定义。这个定义有以下问题:


  • MonadZero MonadPlus 不见了。它们是有用的类。

  • 如果某个符号中的模式匹配失败...




    • Haskell 1.3使用 zero 。左零法则适用(零>> = k =零),所以你知道应该发生什么。
    • Haskell 98使用 fail msg ,其中 msg 是GHC编译器生成的。任何事情都可能发生,并不保证其语义。因此,这对用户来说不是什么功能。结果,Haskell 98的do-notation模式匹配失败的行为是不可预知的!
    • 名称不太一般(例如 map fmap )。不是一个大问题,但它是我眼中的刺。 >总而言之,我认为这些变化并不是最好的。事实上,我认为他们是从Haskell 1.4退步的。 为什么Haskell 98的这些改变,以及为什么这样呢?






      除此之外,我可以想象下面的防御措施:




      • 失败允许用于查找错误。仅适用于程序员,并且仅限于运行时。 (不可移植的!)错误信息不完全是你想要解析的东西。如果你真的关心它,你应该明确地跟踪它。我们现在从 failure 包中有 Control.Failure ,它在这方面做得更好(失败x 的行为大部分类似于)。 开发和使用太难了。课程太少会破坏他们的法律,而这些法律与类型一样重要。 实例限制的函数更容易学习。然而,为什么没有 SimplePrelude ,而大多数类都被删除了?这只是一个魔法宣言,对于学生来说,他们可以管理那么多。 (也许还需要 { - #LANGUAGE RebindableSyntax# - } ,但同样,学生们在复制粘贴的时候非常好。) li>
      • 实例限制函数使错误更具可读性。我比<$ c更经常使用 fmap $ c> map ,那么为什么不 map 和 listMap 改为


      • 为什么这些事情为了Haskell 98而改变,为什么以这种方式?

        Haskell 98对语言进行了大量简化(其中大部分已经被颠倒过来)。目标是改善Haskell作为教学语言,并作出相对保守的选择。

        见例如


        我们认为Haskell 98是一个相当保守的设计。以
        为例,那时多参数类型类被广泛使用
        ,但Haskell 98只有单参数类型类(Peyton
        Jones et al。,1997)。 p>

        在:历史的哈斯克尔



        和:


        Haskell 98绝不会是Haskell的最后一个版本。在
        上相反,我们设计它知道新语言扩展
        (多参数类型类,通用和存在
        量化,模式守卫等等)正在顺利完成。
        但是,Haskell 98将会有一个特殊的状态:意图是
        Haskell编译器将继续支持Haskell 98(即使在
        适当的标志处),即使该语言的后续版本已经为
        定义,所以名称`Haskell 98'将引用一个固定的,稳定的
        语言。


        Haskell98报告



        所以,事情简化了,目标是制定更简单的标准。

        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 and MonadPlus 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, where msg 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!
        • 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 have Control.Failure from the failure package, which does a much better job at this (failure x behaves mostly like zero).
        • "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 than map, so why not map and listMap instead?

        解决方案

        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.

        这篇关于为什么Haskell 98的标准类不如Haskell 1.3?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆