【问题标题】:Implement function overloading in Haskell在 Haskell 中实现函数重载
【发布时间】:2012-01-25 06:58:30
【问题描述】:

我正在解决编写类似于 C++ 程序的 Haskell 代码的问题。

C++ 代码是:

class Rectangle
{
    private:
        int length;
        int width;
    public:
        Rectangle()
        {
            length = 0;
            width = 0;
        }
        Rectangle(int x)
        {
            length = x;
            width =0;
        }
        Rectangle ( int x , int y)
        {
            length = x;
            width = y;
        }
};

为了编写类似的 Haskell 代码,我创建了一个数据类型 Rectangle

data Rectangle = Rectangle Length Width deriving (Eq, Show , Read)
type Length = Int
type Width = Int

然后我想制作一个可以充当构造函数的加载函数。但我不明白如何使用不同数量的参数实现函数重载。 请帮忙。谢谢。

【问题讨论】:

  • 我不会费心尝试在 C++ 之后为 haskell 建模;它只会导致很多痛苦。另外,为什么你的第二个矩形构造函数是一条线?我认为更明智的实现是默认为 (1, 1),如果你得到一个 int,则传入 (x, x),形成一个正方形。
  • 听说过构造函数初始化列表吗?
  • @VladLazarenko:听说过仍在学习的人吗? (提示:你在其中,每个人都是)

标签: haskell


【解决方案1】:

您可以使用记录语法来实现该行为。

data Rectangle = Rectangle {len :: Length, width :: Width} deriving (Eq, Show , Read)
type Length = Int
type Width = Int

rectangle = Rectangle { len = 0, width = 0 }

rectangle :: Rectangle 将成为您的构造函数。

现在您可以定义一些Rectangle 值:

λ> let a = rectangle {len = 1}

λ> a
Rectangle {len = 1, width = 0}

【讨论】:

    【解决方案2】:

    虽然 可以在 Haskell 中进行这种重载,但它不被认为是惯用的,并且可能会在以后导致令人困惑的错误。相反,您应该简单地定义构造数据的函数:

    point :: Rectangle
    point = Rectangle 0 0
    
    line :: Length -> Rectangle
    line l = Rectangle l 0
    
    square :: Int -> Rectangle
    square a = Rectangle a a
    

    这允许您给出描述每个重载的语义的清晰名称,而不是依赖于为消除歧义而提供的参数的数量和类型。

    但是,如果您确实想编写重载版本,您可以使用类型类轻松完成:

    class MakeRectangle a where
      rectangle :: a
    
    instance MakeRectangle Rectangle where
      rectangle = Rectangle 0 0
    
    instance MakeRectangle (Length -> Rectangle) where
      rectangle l = Rectangle l 0
    
    instance MakeRectangle (Length -> Width -> Rectangle) where
      rectangle = Rectangle
    

    您需要在文件顶部使用{-# LANGUAGE FlexibleInstances #-} 来编译它。标准的Text.Printf 库使用了这样的技巧,但我不认为它是 Haskell 中重载的一个特别好的例子;重载值的类型几乎总是有某种结构,而这里它的整个结构由实例决定,这可能会妨碍类型推断;不仅如此,而且没有任何合理的法律来管理实例(实际上,类型太笼统而不允许任何)。

    但如果你真的想这样做,你可以,虽然这通常是个坏主意,但有时(如 printf 的情况)这是完成你想要的界面的唯一方法。

    要在 GHCi 中进行尝试,您需要明确指定您正在使用的类型,否则它将无法解析实例:

    GHCi> rectangle :: Rectangle
    Rectangle 0 0
    GHCi> rectangle (1 :: Length) :: Rectangle
    Rectangle 1 0
    GHCi> rectangle (1 :: Length) (2 :: Width) :: Rectangle
    Rectangle 1 2
    

    【讨论】:

    • 我无法编译程序。错误是multiple declarations for rectangle
    • 您确定要保留缩进吗?您在文件的其他位置是否有另一个 rectangle 声明?如果两者都不是,请将您正在编译的完整文件添加到您的问题中,我会看看。
    • 您忘记在我的代码中包含空格; Haskell 是一种对缩进敏感的语言。
    • 你能解释一下有或没有空格会发生什么吗?
    • 不带空格,给定的rectangle定义为重复顶层定义,classinstance定义为空;使用空格,rectangle 的定义与 classinstance 声明按预期关联。
    【解决方案3】:

    你要找的不就是这个:

    data Rectangle = Point |  Line Int | Rectangle Int Int
    

    【讨论】:

      猜你喜欢
      • 2021-12-04
      • 1970-01-01
      • 1970-01-01
      • 2013-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-28
      • 2019-01-24
      相关资源
      最近更新 更多