2011-12-30 4 views
8

Dựa trên recent exchange, tôi đã bị thuyết phục sử dụng Mẫu Haskell để tạo một số mã để đảm bảo an toàn loại biên dịch theo thời gian.Haskell xem xét tên và loại trường của bản ghi

Tôi cần xem xét các tên và loại trường bản ghi. Tôi hiểu rằng tôi có thể get field names bằng cách sử dụng constrFields . toConstr :: Data a => a -> [String]. Nhưng tôi cần nhiều hơn tên trường, tôi cần biết loại của họ. Ví dụ, tôi cần phải biết tên của các trường có kiểu Bool.

Làm cách nào để tạo một hàm f :: a -> [(String, xx)] trong đó a là bản ghi, String là tên trường và xx là loại trường?

Trả lời

8

Loại phải có sẵn cùng với mọi thứ khác, trong giá trị Info do reify cung cấp. Cụ thể, bạn sẽ nhận được TyConI, có chứa a Dec value, từ đó bạn có thể nhận danh sách Con values specifying the constructors. Một loại bản ghi sau đó sẽ sử dụng RecC, sẽ cung cấp cho bạn danh sách các trường described by a tuple chứa tên trường, cho dù trường đó là nghiêm ngặt và the type.

Nơi bạn đi từ đó phụ thuộc vào những gì bạn muốn làm với tất cả điều này.


Sửa: Vì lợi ích của thực sự chứng minh ở trên, đây là một chức năng nhanh chóng và dơ bẩn thực sự khủng khiếp mà thấy lĩnh vực kỷ lục:

import Language.Haskell.TH 

test :: Name -> Q Exp 
test n = do rfs <- fmap getRecordFields $ reify n 
      litE . stringL $ show rfs 

getRecordFields :: Info -> [(String, [(String, String)])] 
getRecordFields (TyConI (DataD _ _ _ cons _)) = concatMap getRF' cons 
getRecordFields _ = [] 

getRF' :: Con -> [(String, [(String, String)])] 
getRF' (RecC name fields) = [(nameBase name, map getFieldInfo fields)] 
getRF' _ = [] 

getFieldInfo :: (Name, Strict, Type) -> (String, String) 
getFieldInfo (name, _, ty) = (nameBase name, show ty) 

Nhập rằng trong mô-đun khác, chúng tôi có thể sử dụng nó như vậy:

data Foo = Foo { foo1 :: Int, foo2 :: Bool } 

foo = $(test ''Foo) 

Tải trong GHCi, giá trị trong foo[("Foo",[("foo1","ConT GHC.Types.Int"),("foo2","ConT GHC.Types.Bool")])].

Điều đó có cung cấp cho bạn ý tưởng thô không?

+0

Đó chính xác là những gì tôi đang tìm kiếm. Tôi luộc ví dụ của bạn xuống dưới đây: 'introspect n = reify n >> = stringE. show'. Cảm ơn bạn đã hướng dẫn! – Ana