2015-02-17 13 views
15

Trong this talk around the 1:20 mark, Edward Kmett đề cập đến việc thiếu "loại lớp backtracking" trong Haskell. Hãy xem xét các vấn đề của "thiết lập sự bình đẳng" (nơi trật tự và đa dạng được bỏ qua) thực hiện trên danh sách:Có cách giải quyết nào cho việc thiếu loại backtracking không?

equals :: [a] -> [a] -> Bool 

Bởi bản chất của các lớp học loại I không thể cung cấp một sự so sánh hiệu quả O (n ²) nếu tất cả chúng ta phải là Eq a nhưng so sánh hiệu quả các danh sách trong O (n log n) nếu chúng ta có Ord a.

Tôi đã hiểu lý do tại sao cơ sở như vậy sẽ có vấn đề. Đồng thời, Edward nói rằng có những "thủ thuật bạn có thể chơi" đề cập đến các gia đình kiểu mẫu.

Do đó câu hỏi của tôi là, những gì sẽ là một cách giải quyết để đạt được hiệu quả tương tự:

  • một (không hiệu quả) thực hiện mặc định được cung cấp
  • nếu người dùng có thể cung cấp thêm một số thông tin về loại, chúng tôi "mở khóa" triển khai hiệu quả hơn

Cách giải quyết này không nhất thiết phải sử dụng các loại lớp.

Chỉnh sửa: Một số người đề xuất chỉ cần cung cấp equalsefficientEquals làm hai phương pháp riêng biệt. Nói chung tôi đồng ý rằng đây là cách tiếp cận thành ngữ-Haskell hơn. Tuy nhiên, tôi không tin rằng điều này là luôn luôn có thể. Ví dụ, nếu bằng phương pháp trên là bản thân một phần của một lớp học loại:

class SetLike s where 
    equals :: Eq a => s a -> s a -> Bool 

Giả sử rằng lớp này đã được cung cấp bởi người khác vì vậy tôi không thể chỉ cần thêm một chức năng mới cho typeclass. Bây giờ tôi muốn xác định cá thể cho []. Tôi biết rằng [] luôn có thể cung cấp triển khai equals bất kể ràng buộc nào có trên a nhưng tôi không thể cho biết trường hợp của mình để sử dụng phiên bản hiệu quả hơn nếu có thêm thông tin về a.

Có lẽ tôi có thể bọc danh sách trong một loại mới và gắn thẻ nó với một số thông tin loại bổ sung?

+2

Điều này khá thú vị và tôi không biết câu trả lời cho điều này. Nhưng một giải pháp nhanh chóng và bẩn sẽ là xác định một hàm khác như 'effectiveEquals :: (Ord a) => [a] -> [a] -> Bool' và' equals :: (Eq a) => [a] -> [a] -> Bool'. – Shoe

+3

Hãy làm rõ rằng chúng ta đang nói về việc so sánh các danh sách _đánh giá thứ tự_ (và có thể là bội số). Rõ ràng '(==)' không yêu cầu O (n^2) trên danh sách. – chi

+0

IIRC, GHC cho phép một chỉ định '{- # RULE ... equals = effectiveOrdEquals # -}' chỉ được áp dụng nếu kiểm tra kiểu RHS. Bằng cách này, các cuộc gọi được biết đến tĩnh liên quan đến các loại đặt hàng sẽ nhận được phiên bản hiệu quả. – chi

Trả lời

5

Trong kịch bản từ chỉnh sửa, bạn có thể sử dụng một GADT làm bằng chứng Ord hạn của bạn:

{-# LANGUAGE GADTs #-} 

import Data.List 

class SetLike s where 
    equals :: Eq a => s a -> s a -> Bool 

data OrdList a where 
    OrdList :: Ord a=> [a] -> OrdList a 

instance SetLike OrdList where 
    equals (OrdList a) (OrdList b) = sort a == sort b 

Và cho vui đây là một cái gì đó mà sử dụng làm cho việc sử dụng OverlappingInstances lừa tôi đề cập trong nhận xét của tôi. Có rất nhiều cách để làm điều này:

{-# LANGUAGE DefaultSignatures, OverlappingInstances, UndecidableInstances, MultiParamTypeClasses, FlexibleInstances #-} 

import Data.List 

class Equals a where 
    equals :: [a] -> [a] -> Bool 

    default equals :: Ord a=> [a] -> [a] -> Bool 
    equals as bs = sort as == sort bs 

instance Equals Int 
instance Equals Integer 
instance Equals Char 
-- etc. 

instance (Eq a)=> Equals a where 
    equals = error "slow version" 
+0

Thật không may, OverlappingInstances không thực hiện được một số bảo đảm mà chúng ta thường gặp phải với typeclasses, phải không? Tôi thực sự thích giải pháp GADT, mặc dù! – DanielM

Các vấn đề liên quan