2012-01-25 55 views
6

Tôi đang làm việc về vấn đề viết mã Haskell tương tự như chương trình C++.Thực hiện quá tải chức năng trong Haskell

CáC++ mã C là:

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

Để viết mã Haskell tương tự tôi đã làm một kiểu dữ liệu Rectangle

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

Sau đó, tôi nghĩ đến việc thực hiện một chức năng tải mà có thể đóng vai trò là nhà xây dựng. Nhưng tôi không hiểu làm thế nào để thực hiện chức năng quá tải với số lượng khác nhau của các đối số. Xin vui lòng giúp đỡ. Cảm ơn.

+1

Tôi sẽ không bận tâm cố gắng mô hình haskell sau C++; nó sẽ chỉ dẫn đến rất nhiều đau đớn. Ngoài ra, tại sao nhà xây dựng hình chữ nhật thứ hai của bạn là một dòng? Tôi nghĩ rằng một thực hiện hợp lý hơn sẽ được mặc định để (1, 1), và nếu bạn nhận được một int, vượt qua trong (x, x), để tạo thành một hình vuông. – alternative

+0

Bao giờ nghe nói về danh sách khởi tạo constructor? –

+2

@VladLazarenko: Đã bao giờ nghe nói về những người vẫn đang học? (Gợi ý: Bạn là một trong số họ, tất cả mọi người là) –

Trả lời

21

Trong khi nó thể làm quá tải như vậy trong Haskell, nó không được coi là thành ngữ, và có khả năng sẽ dẫn đến sai sót khó hiểu sau này. Thay vào đó, bạn chỉ cần xác định chức năng xây dựng dữ liệu:

point :: Rectangle 
point = Rectangle 0 0 

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

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

này cho phép bạn để cung cấp cho tên rõ ràng là mô tả ngữ nghĩa của mỗi quá tải, chứ không phải dựa vào số lượng và loại của các đối số cho disambiguate mà bạn nghĩa là.

Tuy nhiên, nếu bạn muốn viết phiên bản quá tải, bạn có thể làm điều đó một cách dễ dàng với 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 

Bạn sẽ cần {-# LANGUAGE FlexibleInstances #-} ở phía trên cùng của tập tin của bạn để biên dịch này. Một thủ thuật như thế này được sử dụng bởi thư viện tiêu chuẩn Text.Printf, nhưng tôi sẽ không coi đây là một ví dụ điển hình về quá tải trong Haskell; hầu như luôn có một số cấu trúc cho kiểu giá trị quá tải, trong khi ở đây toàn bộ cấu trúc của nó được quyết định bởi cá thể, có thể nhận được theo cách suy luận kiểu; không chỉ vậy, nhưng không có bất kỳ luật hợp lý nào chi phối các trường hợp (thực sự, loại này quá chung chung để cho phép bất kỳ).

Nhưng nếu bạn thực sự muốn làm điều đó, bạn có thể, và đôi khi nó thường là một ý tưởng tồi, đôi khi (như trong trường hợp printf) đó là cách duy nhất để thực hiện giao diện bạn muốn.

Để thử này ra trong GHCi, bạn sẽ cần phải xác định loại bạn đang sử dụng một cách rõ ràng, hoặc nó sẽ không thể giải quyết các trường hợp:

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

Tôi không thể biên dịch chương trình. Lỗi là 'nhiều khai báo cho hình chữ nhật ' –

+0

Bạn có chắc chắn giữ nguyên thụt đầu dòng không? Bạn có khai báo 'hình chữ nhật' khác ở đâu trong tệp không? Nếu nó không phải của những người, sau đó thêm các tập tin đầy đủ bạn đang biên dịch cho câu hỏi của bạn và tôi sẽ xem xét. – ehird

+1

Bạn quên bao gồm các khoảng trắng từ mã của tôi; Haskell là một ngôn ngữ nhạy cảm thụt đầu dòng. – ehird

22

Bạn có thể sử dụng cú pháp bản ghi để tiếp cận hành vi đó.

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 sẽ là người xây dựng của bạn ở đây.

Bây giờ bạn có thể xác định một số Rectangle giá trị:

λ> let a = rectangle {len = 1} 

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

không phải là những gì bạn đang chỉ đơn giản là tìm kiếm điều này:

data Rectangle = Point | Line Int | Rectangle Int Int 
Các vấn đề liên quan