2015-07-23 20 views
5

là mỗi lớp không phải là một loại trong Haskell:Loại Ord là gì?

Prelude> :t max 
max :: Ord a => a -> a -> a 
Prelude> :t Ord 

<interactive>:1:1: Not in scope: data constructor ‘Ord’ 
Prelude> 

Tại sao điều này không in Ord loại chữ ký?

+2

Lớp học không phải là một loại (ít nhất là theo nghĩa bạn có thể mong đợi). Nhưng nếu bạn muốn tìm hiểu về một loại, bạn sẽ sử dụng ': k' hoặc': i'. ': t' cho bạn biết loại giá trị. –

Trả lời

6

Được rồi, có một vài điều xảy ra đây.

Trước khi bạn viết :t Ord bạn đang tìm kiếm một cái gì đó gọi là Ord trong giá trị namespace; cụ thể nó sẽ phải là một nhà xây dựng, vì tên bắt đầu bằng một chữ cái viết hoa.

Haskell giữ các loại và giá trị hoàn toàn riêng biệt; không có mối quan hệ giữa tên của một loại và tên của các nhà xây dựng của một loại. Thông thường khi chỉ có một hàm tạo, mọi người sẽ sử dụng cùng tên với kiểu. Ví dụ là data Foo = Foo Int. Điều này tuyên bố hai thực thể được đặt tên mới: loại Foo và hàm tạo Foo :: Int -> Foo. Nó không thực sự là một ý tưởng tốt để nghĩ về nó như chỉ cần thực hiện một loại Foo có thể được sử dụng cả trong các biểu thức loại và để xây dựng Foo s. Bởi vì cũng phổ biến là các khai báo như data Maybe a = Nothing | Just a. Ở đây có 2 nhà thầu khác nhau cho Maybe aMaybe không phải là tên của bất kỳ điều gì ở cấp độ giá trị.

Vì vậy, chỉ vì bạn đã thấy Ord trong biểu thức loại không có nghĩa là có tên Ord ở cấp giá trị để bạn có thể yêu cầu loại với :t. Ngay cả khi có, nó sẽ không nhất thiết phải có liên quan hàng đầu tên loại cấp Ord.

Điểm thứ hai cần làm rõ là không, các lớp không có trong các loại thực tế. Một lớp là đặt các loại (tất cả đều hỗ trợ giao diện được xác định trong lớp), nhưng nó không phải là một loại chính nó.

Trong vanilla, loại lớp Haskell chỉ là "phụ". Bạn có thể khai báo chúng với khai báo class, khởi tạo chúng với khai báo instance và sử dụng chúng theo cú pháp đặc biệt gắn liền với các loại (thứ còn lại của mũi tên =>) làm các ràng buộc về biến kiểu. Nhưng chúng không thực sự tương tác với phần còn lại của ngôn ngữ, và bạn không thể sử dụng chúng trong phần chính của chữ ký kiểu (thứ bên phải của mũi tên `=>).

Tuy nhiên, với tiện ích mở rộng ConstraintKinds bật, hãy nhập các lớp làm trở thành những thứ bình thường tồn tại trong không gian tên loại, giống như Maybe. Chúng vẫn không có nghĩa là không bao giờ có bất kỳ giá trị nào có dạng như vậy, vì vậy bạn không thể sử dụng Ord hoặc Ord Int làm đối số hoặc kiểu trả về trong hàm hoặc có [Ord a] hoặc bất kỳ thứ gì tương tự.

Trong đó chúng là các nhà xây dựng kiểu giống như kiểu Maybe. Maybe là tên bị ràng buộc trong không gian tên loại, nhưng không phải là một loại loại như vậy; không có giá trị nào có loại chỉ là Maybe, nhưng Maybe có thể được sử dụng làm phần của một biểu thức xác định loại, như trong Maybe Int.

Nếu bạn không quen thuộc với các loại, có thể bỏ qua mọi thứ tôi đã nói từ ConstraintKinds trở đi; bạn có thể sẽ tìm hiểu về các loại cuối cùng, nhưng chúng không phải là một tính năng bạn cần biết nhiều về một người mới bắt đầu. Tuy nhiên, nếu bạn là gì, thì ConstraintKinds sẽ tạo ra một loại đặc biệt Constraint và có các ràng buộc kiểu chữ (bên trái của mũi tên =>) chỉ là các loại mức thông thường loại Constraint thay vì cú pháp mục đích đặc biệt. Điều này có nghĩa rằng Ord là một điều loại cấp, và chúng tôi có thể yêu cầu nó loại với lệnh :k trong GHCI:

Prelude> :k Ord 
* -> Constraint 

nào có ý nghĩa; max có loại Ord a => a -> a -> a, vì vậy Ord a phải có loại Constraint. Nếu Ord có thể được áp dụng cho một loại thông thường để mang lại một ràng buộc, nó phải có loại * -> Constraint.

+0

Tôi ước chúng ta không sử dụng từ "loại" theo cách mâu thuẫn lẫn nhau sao cho "Có lẽ không phải là một loại" và "Có thể là một loại cao cấp hơn" cả hai đều có thể là câu đúng. –

+0

Vâng, chúng ta thực sự cần một thuật ngữ ít phức tạp hơn "loại mức độ" cho "những thứ chúng ta có thể sử dụng trong các biểu thức kiểu, cho dù chúng có thể là các loại giá trị" hay không. Nếu không viết tắt là không thể tránh khỏi. Ngữ cảnh phụ thuộc của từ "loại" dường như làm việc tốt cho các chuyên gia, nhưng nó làm cho nó rất khó khăn để chọn công cụ này lên hữu cơ. – Ben

1

Không hoàn toàn. Bạn có thể áp đặt các ràng buộc kiểu, vì vậy Ord a => a là một loại, nhưng Ord a thì không. Ord a => a có nghĩa là "bất kỳ loại a nào có ràng buộc rằng nó là một phiên bản của Ord".

Lỗi là do :t mong đợi một biểu thức. Khi GHCi cố gắng giải thích Ord như một biểu thức, gần nhất nó có thể nhận được là một nhà xây dựng dữ liệu, vì đây là những hàm duy nhất trong Haskell có thể bắt đầu bằng chữ in hoa.

+0

@DanielWagner Tôi nghĩ rằng điểm ở đây là bởi vì ': t' mong đợi một biểu thức, ghci phải giải thích' Ord' là một hàm tạo dữ liệu: chỉ định chữ hoa duy nhất hợp lệ để viết sau khi ': t' là một hàm tạo dữ liệu. Vì vậy, trong khi tôi nghĩ rằng nó đã được từ ngữ kém, nó không hoàn toàn không đúng chỗ vào cuối câu đó. – amalloy

+0

@ DanielWagner điểm tốt, hãy để tôi tinh chỉnh câu trả lời của tôi để chuyển trọng tâm một chút. – Alec

2

Ord không phải là loại, nhưng là typeclass. Nó không có một loại, nhưng một loại:

Prelude> :k Ord 
Ord :: * -> Constraint 

Typeclasses là một trong những điều tuyệt vời về Haskell. Kiểm tra 'em ra :-)

3

Ord không phải là một loại; đó là một chiếc máy đánh chữ. Typeclasses cho phép bạn liên kết các hoạt động được hỗ trợ với một kiểu đã cho (tương tự như các giao diện trong Java hoặc các giao thức trong Objective-C). Loại (ví dụ: Int) là "phiên bản" của kiểu chữ (ví dụ: Ord) có nghĩa là loại hỗ trợ các chức năng của Ord typeclass (ví dụ: compare, <, > v.v.).

Bạn có thể nhận được thông tin nhất về một typeclass sử dụng :i trong ghci, trong đó cho thấy bạn các chức năng liên quan đến việc typeclass và những loại là trường hợp của nó:

ghci > :i Ord 
class Eq a => Ord a where 
    compare :: a -> a -> Ordering 
    (<) :: a -> a -> Bool 
    (>=) :: a -> a -> Bool 
    (>) :: a -> a -> Bool 
    (<=) :: a -> a -> Bool 
    max :: a -> a -> a 
    min :: a -> a -> a 
    -- Defined in ‘GHC.Classes’ 
instance Ord a => Ord (Maybe a) -- Defined in ‘Data.Maybe’ 
instance (Ord a, Ord b) => Ord (Either a b) 
    -- Defined in ‘Data.Either’ 
instance Ord Integer -- Defined in ‘integer-gmp:GHC.Integer.Type’ 
instance Ord a => Ord [a] -- Defined in ‘GHC.Classes’ 
...