2011-06-08 22 views
14

Tôi đang cố gắng để mã hóa một danh sách các mục mà có các loại hạn chế được trường hợp của một số loại lớp:Danh sách các mặt hàng của các loại bị hạn chế bởi typeclass

{-# LANGUAGE RankNTypes, TypeSynonymInstances, LiberalTypeSynonyms #-} 
module Test where 

class Someable a where 
    some :: a -> String 

data Some = Some String 

type SomeGroup = forall a. Someable a => [a] 

instance Someable Some where 
    some (Some v) = v 

instance Someable SomeGroup where 
    some (x:xs) = (some x) ++ ", " ++ (some xs) 

main = do 
    putStrLn $ show.some [Some "A", [Some "B", Some "C"]] 

Nhưng biên soạn thất bại với lỗi:

Test.hs:14:10: 
    Illegal polymorphic or qualified type: SomeGroup 
    In the instance declaration for `Someable SomeGroup' 

có vẻ như tôi thậm chí thất bại trong việc xác định dụ cho loại đồng nghĩa ...

tôi nhận thức được heterogenous collections bài viết wiki, nhưng muốn biết lý do tại sao chính xác cách tiếp cận của tôi không hoạt động - nó có vẻ tự nhiên đối với tôi để xác định loại bằng cách hạn chế thu thập chỉ để chứa các mục có loại là thể hiện của một số loại lớp.

+1

Những gì bạn đang cố gắng làm ở đây có ý nghĩa, nhưng nó không được Haskell hỗ trợ tốt và thường là một triệu chứng của thiết kế không phải là thành ngữ. Nếu bạn tò mò về cách làm điều đó, @hammar cung cấp cho bạn một điểm khởi đầu. Nếu bạn gặp phải tình huống này trong mã thực, bạn có thể nên suy nghĩ lại cách tiếp cận của mình. –

Trả lời

9

Nếu tôi hiểu chính xác mọi thứ, cần phải có một kiểu dữ liệu bao quanh sự tồn tại để có một nơi để lưu trữ type class dictionary cùng với mỗi phần tử.

Thêm một số giấy gói làm cho nó hoạt động:

{-# LANGUAGE ExistentialQuantification, TypeSynonymInstances #-} 

module Test where 

class Someable a where 
    some :: a -> String 

data Some = Some String 

data SomeWrapper = forall a. Someable a => SomeWrapper a 

type SomeGroup = [SomeWrapper] 

instance Someable Some where 
    some (Some v) = v 

instance Someable SomeWrapper where 
    some (SomeWrapper v) = some v 

instance Someable SomeGroup where 
    some (x:xs) = (some x) ++ ", " ++ (some xs) 

main = do 
    putStrLn $ some [SomeWrapper (Some "A"), SomeWrapper [SomeWrapper (Some "B"), SomeWrapper (Some "C")]] 

Tất nhiên, đây là một chút xấu xí. Tôi không biết bất kỳ cách nào tốt hơn, thật không may.

+2

Lưu ý rằng loại bạn đã xác định khác với loại trong câu hỏi: '∀ x. C x => [x] 'khác biệt với' [∀ x. C x => x] '. –

+0

@camccann: Bạn có chắc là bạn đang đọc mã của tôi đúng không? 'SomeWrapper' là' forall x. C x => x', và tôi sử dụng '[SomeWrapper]'. – hammar

+0

@hammar: Vâng, và câu hỏi có một cách khác. So sánh các định nghĩa của 'SomeGroup'. –

3

Bạn cũng có thể nấu gì đó bằng GADT. Điều đó có thể hơi ngắn hơn trong một số trường hợp và nó làm cho rõ ràng loại từ điển nào có sẵn sau khi khớp mẫu.

Dưới đây là một biến thể nhẹ ví dụ của bạn:

{-# LANGUAGE GADTs #-} 
class Someable a where 
    some :: a -> String 

instance Someable Int where 
    some n = show n 

data SomeString = SomeString String 
instance Someable SomeString where 
    some (SomeString s) = s 

data SomeGroup where 
    Nil :: SomeGroup 
    Cons :: Someable a => a -> SomeGroup -> SomeGroup 

instance Someable SomeGroup where 
    some Nil = "" 
    some (Cons x Nil) = some x 
    some (Cons x xs) = some x ++ ", " ++ some xs 

list = Cons (3::Int) (Cons (SomeString "abc") (Cons (42::Int) Nil)) 
main = print . some $ list 

Một vài ghi chú nhỏ:

  • Bạn quên trường hợp cơ sở cho các đệ quy :)
  • putStrLn . show cũng giống như print .
  • Bạn phải nêu rõ loại số rõ ràng là Int vì số nguyên nguyên được xử lý đặc biệt, nghĩa là 42 được dịch sang fromInteger 42 loại Num a => a. Một chút clunky khi xây dựng danh sách trực tiếp, nhưng hầu hết thời gian nó sẽ hoạt động trơn tru hơn.
  • Tất nhiên, bạn có thể xác định đường cú pháp của riêng bạn cho Cons -ing các yếu tố vào danh sách, nhưng cú pháp sẽ không bao giờ trông đẹp như cú pháp tích hợp của Haskell!

Và điểm chính là bạn mất việc sử dụng tất cả các chức năng danh sách chuẩn. Tôi thường sử dụng loại giải pháp này khi nhu cầu xử lý danh sách của tôi rất hạn chế; mặt khác, gấp được viết một cách nhanh chóng đủ ... Số dặm của bạn sẽ thay đổi mặc dù, tôi không biết những gì bạn thực sự muốn sử dụng danh sách này cho.

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