Перегрузка функции реализации в 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}