Перегрузка функции реализации в Haskell

Я работаю над проблемой написания кода Haskell, похожего на программу на C++.

код 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, я сделал прямоугольник типа данных

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

затем я подумал о создании функции загрузки, которая может выступать в качестве конструктора. Но я не понимаю, как реализовать перегрузку функций с разным количеством аргументов. Пожалуйста помочь. Спасибо.

3 ответов


а то is возможно сделать такую перегрузку в Haskell, это не считается идиоматическим и, вероятно, приведет к путанице ошибок позже. Вместо этого, вы должны просто определить функции, которые создают данные:

point :: Rectangle
point = Rectangle 0 0

line :: Length -> Rectangle
line l = Rectangle l 0

square :: Int -> Rectangle
square a = Rectangle a a

это позволяет дать четкие имена, которые описывают семантика каждой перегрузки, а не полагаться на количество и тип аргументов, данных для устранения неоднозначности, которую вы имеете в виду.

однако, если вы хотите напишите перегруженную версию, вы можете сделать это легко с помощью typeclasses:

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

вы можете использовать синтаксис записи для достижения этого поведения.

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}

Не то, что вы ищете просто:

data Rectangle = Point |  Line Int | Rectangle Int Int