2014-10-10 17 views
12

Tôi đang làm việc với Data.Typeable và đặc biệt tôi muốn có thể tạo ra các loại chính xác của một loại cụ thể (giả sử *). Vấn đề mà tôi đang chạy vào đó là TypeRep cho phép chúng ta làm như sau (làm việc với các phiên bản trong GHC 7.8):Có thể lấy Kiểu Loại Constructor trong Haskell không?

let maybeType = typeRep (Proxy :: Proxy Maybe) 
let maybeCon = fst (splitTyConApp maybeType) 
let badType = mkTyConApp maybeCon [maybeType] 

Đây badType là theo nghĩa các đại diện của các loại Có lẽ Có lẽ, đó là không phải là loại hợp lệ của bất kỳ Loại nào:

> :k Maybe (Maybe) 

<interactive>:1:8: 
    Expecting one more argument to ‘Maybe’ 
    The first argument of ‘Maybe’ should have kind ‘*’, 
     but ‘Maybe’ has kind ‘* -> *’ 
    In a type in a GHCi command: Maybe (Maybe) 

Tôi không thể viết chương trình này ở mức độ đủ thông minh để tránh tạo kiểu như vậy khi chạy. Tôi có thể làm điều này với các điều khoản cấp dữ liệu với TypeRep. Lý tưởng nhất, tôi sẽ có một cái gì đó giống như

data KindRep = Star | KFun KindRep KindRep 

và có một chức năng kindOf với kindOf Int = Star (có lẽ thực sự kindOf (Proxy :: Proxy Int) = Star) và kindOf Maybe = KFun Star Star, vì vậy mà tôi có thể "loại kiểm tra lại" giá trị TypeRep tôi.

Tôi nghĩ rằng tôi có thể làm điều này bằng tay với một kiểu chữ polykinded như Typeable, nhưng tôi không muốn viết trường hợp của riêng tôi cho tất cả mọi thứ. Tôi cũng không muốn quay trở lại GHC 7.6 và sử dụng thực tế là có các loại lớp riêng biệt cho các loại có thể đánh loại khác nhau. Tôi mở cửa cho các phương pháp nhận được thông tin này từ GHC.

+0

'typeOf1' và' Typeable1' (và bạn bè) vẫn được xuất từ ​​'Data.Typeable' ... chúng có thể sử dụng được ở 7.8. –

Trả lời

12

Chúng ta có thể lấy loại kiểu, nhưng chúng ta cần phải ném toàn bộ các phần mở rộng ngôn ngữ tại GHC để làm như vậy, bao gồm cả (trong trường hợp này) vượt quá UndecidableInstancesAllowAmbiguousTypes.

{-# LANGUAGE KindSignatures #-} 
{-# LANGUAGE FlexibleInstances #-} 
{-# LANGUAGE PolyKinds #-} 
{-# LANGUAGE ScopedTypeVariables #-} 
{-# LANGUAGE UndecidableInstances #-} 
{-# LANGUAGE AllowAmbiguousTypes #-} 

import Data.Proxy 

Sử dụng định nghĩa của bạn cho một KindRep

data KindRep = Star | KFun KindRep KindRep 

chúng ta định nghĩa lớp của Kindable điều mà loại có thể được xác định

class Kindable x where 
    kindOf :: p x -> KindRep 

Các trường hợp đầu tiên của việc này là dễ dàng, tất cả mọi thứ thuộc loại *Kindable:

instance Kindable (a :: *) where 
    kindOf _ = Star 

Bắt loại loại cao hơn là khó. Chúng tôi sẽ cố gắng nói rằng nếu chúng ta có thể tìm ra loại tranh cãi của nó và loại kết quả của việc áp dụng nó vào một cuộc tranh luận, chúng ta có thể tìm ra loại của nó. Thật không may, vì nó không có một đối số, chúng tôi không biết loại đối số của nó sẽ là gì; đây là lý do tại sao chúng tôi cần AllowAmbiguousTypes.

instance (Kindable a, Kindable (f a)) => Kindable f where 
    kindOf _ = KFun (kindOf (Proxy :: Proxy a)) (kindOf (Proxy :: Proxy (f a))) 

kết hợp, các định nghĩa này cho phép chúng tôi viết những thứ như

kindOf (Proxy :: Proxy Int) = Star 
kindOf (Proxy :: Proxy Maybe) = KFun Star Star 
kindOf (Proxy :: Proxy (,)) = KFun Star (KFun Star Star) 
kindOf (Proxy :: Proxy StateT) = KFun Star (KFun (KFun Star Star) (KFun Star Star)) 

Chỉ cần đừng cố gắng xác định loại của một loại polykinded như Proxy

kindOf (Proxy :: Proxy Proxy) 

mà may mắn thay kết quả trong một lỗi trình biên dịch chỉ trong một khoảng thời gian hữu hạn.

+0

FYI, hầu hết các bậc thầy của Haskell mà tôi đã gặp phải là 'UndecidableInstances' là một điều hợp lý. Tôi sẽ tưởng tượng 'AllowAmbiguousTypes' có thể là một chút ở phía râm mặc dù điều đó làm cho suy luận một chút flaky? – dfeuer

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