2012-01-25 25 views
18

Các Haskell 2010 Báo cáo Ngôn ngữ quốc gia trong phần 20.10.1.1 rằng:Có lý do chính đáng nào khiến `deleteBy` không có loại chung nhất?

deleteBy :: (a -> a -> Bool) -> a -> [a] -> [a] 

Trong thực tế, việc thực hiện trong GHC library sẽ cho phép

deleteBy :: (b -> a -> Bool) -> b -> [a] -> [a] 

nhưng thực sự hạn chế các loại với một cựu với chú thích.

Do đó, người ta không thể nói, ví dụ:

foo = deleteBy fsteq 42 [(43, "foo"), (44, "bar"), (42, "baz")] where 
    fsteq a (b,_) = a == b 

Int là không giống như (Int, String).

Có lý do chính đáng nào cho việc này không?

Lý do tôi yêu cầu là, nếu không có lý do chính đáng cho nó, tôi sẽ bao gồm deleteBy với loại chung hơn trong cổng dữ liệu Frege. Hiện tại tôi đang thực hiện. Nhưng có lẽ tôi đang nhìn cái gì đó?

EDIT: Như @hammar đã chỉ ra, điều này cũng áp dụng cho các chức năng khác xxx.

Trả lời

11

generalising loại deleteBy vi phạm tiêu chuẩn theo một cách rất thực tế: các chương trình Haskell hoàn toàn hợp lệ trở thành không hợp lệ, nhờ quá tải chưa được giải quyết.

Dưới đây là một cuộc biểu tình:

class (Num a) => Magic a where 
    magic :: a -> Bool 

sameMagic :: (Magic a, Magic b) => a -> b -> Bool 
sameMagic a b = magic a == magic b 

test :: (Magic a) => [a] 
test = deleteBy sameMagic 42 [1234] 

Trong Haskell, chương trình này là hoàn toàn tốt, đánh máy; Loại hạn chế của deleteBy đảm bảo rằng 42 được đảm bảo có cùng loại với 1234. Với tổng quát deleteBy, đây không phải là trường hợp, và do đó loại 42 là mơ hồ, làm cho chương trình không hợp lệ. (Nếu bạn muốn có một ví dụ ít giả tạo, hãy xem xét một chức năng mà so sánh hai Integral giá trị với toInteger.)

Vì vậy, có lẽ không có lý do chính đáng cho loại bị hạn chế này (mặc dù nếu deleteBy là để được khái quát hóa, tôi muốn Hammar của phiên bản cho đề xuất của bạn), nhưng tổng quát nó không vi phạm tiêu chuẩn và có thể phá vỡ các chương trình hợp lệ.

+1

Đó là loại nhận xét sâu sắc mà tôi đang tìm kiếm. Cung cấp cho tôi một cái gì đó để suy nghĩ về. – Ingo

+0

Đây là một câu trả lời rất sâu sắc! – danr

+0

Nhưng không nên 42 được giải quyết thành 'Số nguyên' theo quy tắc loại mặc định? – haskelline

10

Tôi đoán đó là đối xứng với các hàm xxxBy khác. Tuy nhiên, loại của bạn vẫn không cần thiết cụ thể. Tôi thích điều này.

deleteBy :: (a -> Bool) -> [a] -> [a] 

Sau đó bạn có thể viết ví dụ bạn sử dụng ứng dụng phần:

foo = deleteBy (fsteq 42) [(43, "foo"), (44, "bar"), (42, "baz")] where 
    fsteq a (b,_) = a == b 
+0

Ngoại trừ bộ lọc đó sẽ xóa * tất cả * phần tử bằng nhau, trong đó deleteBy chỉ phải xóa phần tử đầu tiên. – Ingo

+0

@Ingo: Rất tiếc! Bạn hoàn toàn đúng. 'filter' sẽ không thực hiện công việc ở đây. – hammar

+1

Chắc chắn, có nhiều cách xung quanh nó, nhưng bạn thấy đấy, mục tiêu là phải tuân theo tiêu chuẩn (Haskell 2010, trong trường hợp này). Câu hỏi đặt ra là nếu nó vi phạm tiêu chuẩn nếu một là tổng quát hơn một chút. – Ingo

7

Ingo,

trong câu hỏi ban đầu của bạn, có vẻ như bạn đang thắc mắc tại sao Haskell Báo cáo chỉ rõ deleteBy như thế này . Vì vậy, nếu không có lý do chính đáng, bạn có thể sử dụng một định nghĩa khác trong Frege (ngụ ý bạn không quan tâm đến sự phù hợp của Báo cáo Haskell).

Như Hammar nói, nó giống như các chức năng khác xxxBy: xóa sử dụng (==), deleteBy mất một vị đó là như (==): loại (a -> a - > Bool) và được cho là một mối quan hệ tương đương. Trong khi hệ thống kiểu không thể kiểm tra nếu biến vị ngữ thực sự là một quan hệ tương đương, thì nó là hợp đồng hàm. Vì vậy, nó rất dễ dàng để hiểu những gì xxxBy có nghĩa là nếu bạn biết những gì xxx có nghĩa là. Và có lẽ nó không phải là trường hợp cho deleteBy, nhưng trong một số trường hợp, việc thực hiện có thể được tối ưu hóa theo giả thiết rằng biến vị ngữ có các thuộc tính được chỉ định (quan hệ tương đương hoặc tổng số thứ tự, vv).

Nhưng trong nhận xét của bạn về câu trả lời của Hammar, bạn hỏi xem liệu việc triển khai tổng quát hơn có vi phạm báo cáo hay không. Vâng, nếu loại là khác nhau thì đó là nghĩa đen là một sự vi phạm, phải không? Vì các chương trình không nên biên dịch theo báo cáo sẽ được trình biên dịch của bạn chấp nhận. Vì vậy, nó làm phát sinh một vấn đề về tính di động: nếu mã của bạn sử dụng phiên bản tổng quát hơn, thì nó có thể không biên dịch trên một triển khai khác phù hợp với đặc điểm kỹ thuật. Bên cạnh đó, nó đi với yêu cầu tương quan tương đương.

Vì vậy, nếu bạn muốn có một hàm tổng quát hơn, tại sao không chỉ định nghĩa một hàm khác với một tên khác? Ví dụ: xóaNếu.

(Tôi muốn nhận xét về câu trả lời Hammar, nhưng tôi không thể vì vậy tôi đã viết nó ở đây.)

+0

Rafael, tốt bạn đã viết câu trả lời này, vì vậy tôi có thể +1 nó. – Ingo

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